Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[expo-sqlite] Updated to allow usage with encrypted SQLite files #8242

Closed
wants to merge 16 commits into from

Conversation

gurs1kh
Copy link

@gurs1kh gurs1kh commented May 11, 2020

Why

There is a need to be able to use encrypted SQLite files in Expo as expressed in several places, like: Expo feature requests (Canny), the Expo forums, StackOverflow, etc.
Here's a few examples:
https://expo.canny.io/feature-requests/p/sqlite-encrypted-database
https://forums.expo.io/t/expo-sqlite-encrypted-support/19493
https://forums.expo.io/t/storing-sqlite-file-securely/10377
https://stackoverflow.com/questions/58688148/encrypt-database-in-react-with-expo

How

In order to be able to use encrypted databases, I integrated SQLCipher into the existing expo-sqlite package.

Test Plan

I've tested added tests, but sadly I wasn't able to run them properly on my machine. I think there was some sort of clash with the installed Expo Client. I'd appreciate if someone could confirm that these work as expected.
Along with tests, I managed to get this to work with a personal project and the expo examples/with-sqlite project (though I had to eject to be able to use my updated package).

@akaldesign
Copy link

Very important to be resolved for the future of our app roadmap.
We cannot migrate our apps to RN.

@gurs1kh
Copy link
Author

gurs1kh commented May 12, 2020

@sjchmiela @mczernek I've gotten the builds succeeding to the best of my abilities. The remaining failures are both due to missing environment variables.
Can one of you take a look at them?

Here's the output on CircleCI:

#!/bin/bash -eo pipefail
yarn danger ci
yarn run v1.22.4
$ /home/circleci/project/docs/node_modules/.bin/danger ci
The DANGER_GITHUB_API_TOKEN/DANGER_BITBUCKETSERVER_HOST/DANGER_GITLAB_API_TOKEN environmental variable is missing
Without an api token, danger will be unable to comment on a PR
Error:  Error: Cannot use authenticated API requests.
    at Object.getPlatformForEnv (/home/circleci/project/docs/node_modules/danger/distribution/platforms/platform.js:76:11)
    at Object.<anonymous> (/home/circleci/project/docs/node_modules/danger/distribution/commands/ci/runner.js:81:57)
    at step (/home/circleci/project/docs/node_modules/danger/distribution/commands/ci/runner.js:32:23)
    at Object.next (/home/circleci/project/docs/node_modules/danger/distribution/commands/ci/runner.js:13:53)
    at fulfilled (/home/circleci/project/docs/node_modules/danger/distribution/commands/ci/runner.js:4:58)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Exited with code exit status 1

Copy link
Contributor

@sjchmiela sjchmiela left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apart from this couple of comments I'm afraid of:

  • app size impact
  • WebSQL compatibility — big feature of expo-sqlite and Expo modules as a whole is cross-platform compatibility — as far as I know it's currently not possible to use encrypted SQLite databases on Web. What do you think about it @ide?

packages/expo-sqlite/android/build.gradle Outdated Show resolved Hide resolved
CHANGELOG.md Outdated Show resolved Hide resolved
packages/expo-sqlite/ios/EXSQLite/EXSQLite.m Outdated Show resolved Hide resolved
packages/expo-sqlite/ios/EXSQLite/EXSQLite.m Outdated Show resolved Hide resolved
packages/expo-sqlite/ios/EXSQLite.podspec Outdated Show resolved Hide resolved
@ide
Copy link
Member

ide commented May 22, 2020

Will need to think about the implications some more but I probably won't get around to this soon. Ease of installation and size are both important. Also want to think about the threat model here. Is there a way for an app to say to the OS that all of its data should be encrypted? If so, then encrypting just the SQLite DB is superficial.

sjchmiela added a commit that referenced this pull request May 29, 2020
# Why

I wanted to clear the way for #8242 to be landed (or not). I noticed that web support doesn't look like it should work and that it isn't tested anywhere.

# How

- added SQLite test suite to set run on web
- changed the way we fetch values in test suite from using `._array[0]` to `.item(0)`
- added explanations in `SQLite.types.ts` about why we may need a copy of `@types/websql`
- added `Window` declaration to types declarations
- removed `@types/websql` dependency as it's not even importable
- fixed web counterpart — `SQLite.web.ts` — by fixing the method header and gracefully handling situation where `openDatabase` is not available (I think).

# Test Plan

Test suite passes.
Copy link
Contributor

@sjchmiela sjchmiela left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this contribution. A couple of things still left to find out:

  • how does this affect app size? If noticeably, we could make it an optional addition
  • strip the key when run on Web
  • add tests to test-suite run on all platforms that will let us ensure that both openDatabase(string) & openDatabase({…}) work and that an encrypted database is not readable when an invalid key is provided

packages/expo-sqlite/ios/EXSQLite/EXSQLite.m Outdated Show resolved Hide resolved
packages/expo-sqlite/ios/EXSQLite/EXSQLite.m Outdated Show resolved Hide resolved
packages/expo-sqlite/ios/EXSQLite/EXSQLite.m Outdated Show resolved Hide resolved
packages/expo-sqlite/ios/EXSQLite/EXSQLite.m Outdated Show resolved Hide resolved
packages/expo-sqlite/CHANGELOG.md Outdated Show resolved Hide resolved
packages/expo-sqlite/android/build.gradle Outdated Show resolved Hide resolved
docs/pages/versions/unversioned/sdk/sqlite.md Outdated Show resolved Hide resolved
CHANGELOG.md Outdated Show resolved Hide resolved
@@ -81,16 +90,28 @@ function addExecMethod(db: any): WebSQLDatabase {
}

export function openDatabase(
name: string,
fileInfo: SQLiteFileInfo | string,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also add support for this to SQLite.web.ts so it strips key from the fileInfo and uses only name if an object is provided?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have made the change, but would appreciate if you could double-check SQLite.web.ts to see if I did what you were expecting

@gurs1kh
Copy link
Author

gurs1kh commented Jun 3, 2020

  • how does this affect app size? If noticeably, we could make it an optional addition

Do you know of a good way to check this?

  • add tests to test-suite run on all platforms that will let us ensure that both openDatabase(string) & openDatabase({…}) work and that an encrypted database is not readable when an invalid key is provided

I've already added these tests. Is there anything specific that I missed?

Co-authored-by: Stanisław Chmiela <sjchmiela@users.noreply.github.com>
@gurs1kh
Copy link
Author

gurs1kh commented Jun 23, 2020

  • how does this affect app size? If noticeably, we could make it an optional addition

Do you know of a good way to check this?

@sjchmiela Just thought I'd give you a reminder

Copy link
Contributor

@sjchmiela sjchmiela left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When it comes to measuring app size impact:

  • first, assemble an APK release of bare-expo on master, without your changes (you may need to use some temporary key to sign the app)
  • then, assemble an APK release of bare-expo on your branch, with the changes
  • see the difference in APK sizes
  • in Xcode — archive the project on master, note the size of the xcarchive
  • archive the project on your branch, see the difference.

Sorry for the delay! 😕

@@ -1,2 +1,11 @@
export const { openDatabase } = global;
export function openDatabase(fileInfo, ...args) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, so… could you please rebase this PR on top of master? Before getting back to you I've ensured that SQLite works on Web properly and changed this file a little bit — #8518.

@@ -58,6 +58,14 @@ - (NSValue *)openDatabase:(NSString *)dbName
if (sqlite3_open([path UTF8String], &db) != SQLITE_OK) {
return nil;
};

if (!dbKey) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (!dbKey) {
if (dbKey) {

Sorry for making that suggestion before — I misunderstood dbKey != NULL and proposed !dbKey changing the if completely. dbKey != NULL means if dbKey is non-empty which should translate to Obj-C-y if (dbKey) (if dbKey is truthy)


if (!dbKey) {
const char *key = [dbKey UTF8String];
if (!key) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (!key) {
if (key) {

@gurs1kh
Copy link
Author

gurs1kh commented Sep 6, 2020

@sjchmiela I'm running into too many issues when trying to build the app. I think it might be easier if someone who already has expo properly set up could do it. I've put up comment asking someone to help on https://expo.canny.io/feature-requests/p/sqlite-encrypted-database, but I'm not sure how soon we can get someone to do it.

@gurs1kh
Copy link
Author

gurs1kh commented Dec 8, 2020

@sjchmiela I managed to work through the issues I faced building the apps. Here is what I found:

Old size New size Size increase
Android (APK) 41.6 MB 47.4 MB 13.9%
iOS (Archive) 263.6 MB 281.8 MB 6.9%

I can go through and rebase the PR off of the latest commit in master, but I just wanted to get your thoughts on the app size increase before I do so. Just thought it'd be good to see if it's even worth going through the work of doing that or not.

@ide
Copy link
Member

ide commented Dec 9, 2020

A 14% increase is probably too much, especially coming from a proprietary library that we'll end up wanting to remove. I think the path forward is to use the OS's own encryption capabilities where possible.

For example, this might be the appropriate approach on iOS: https://developer.apple.com/documentation/uikit/protecting_the_user_s_privacy/encrypting_your_app_s_files. Android also has some disk encryption too: https://source.android.com/security/encryption/file-based.

The threat model we'd consider is an attacker getting physical access to someone else's device, especially if the device is off. We can't really prevent a user accessing data on their own device and consider that scenario to be out of scope. Fundamentally speaking, if an app has access to data, then the user using that app has access to the data -- to prevent a user from accessing data, it needs not to be sent to the device in the first place.

The disk-level encryption on Android and iOS seem reasonable to adopt. Perhaps we need to identify a set of options that work across platforms (e.g. disallow access until first unlock) that map to Android and iOS's options, and then create a universal API to expose those options and apply them to the SQLite file.

@gurs1kh
Copy link
Author

gurs1kh commented Dec 11, 2020

Though I would say that there definitely are reasons to encrypt the sqlite DB itself, I do understand how the app size increase is problematic. Anyways, thanks for entertaining the possibility of adding this feature. Guess we'll just have to use a bare workflow.

@gurs1kh gurs1kh closed this Dec 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants