forcedotcom / SalesforceMobileSDK-ReactNative

BSD 3-Clause "New" or "Revised" License
49 stars 54 forks source link

Salesforce Mobile SDK SmartStore Encryption (React-Native) #392

Open mingfeng-alphline opened 1 month ago

mingfeng-alphline commented 1 month ago

Our team recently developed a custom mobile app using Salesforce Mobile SDK (version 12.0.1) and utilized the SmartStore feature for local data storage. After conducting a penetration test on the app, we discovered that the SmartStore database files are not encrypted.

We would like to understand if there is a built-in way to enable encryption for SmartStore within the Salesforce Mobile SDK or if additional configuration is required on our end.

Questions:

Does the SF Mobile SDK ensure that all data within SmartStore soups is encrypted automatically, or are there certain data types or fields that require manual encryption? How can we verify that the encryption is successfully applied to SmartStore soups, both globally and at the field level? Are there any known limitations or bugs in the current version of the Salesforce Mobile SDK (12.0.1) we are using related to data encryption in SmartStore? Is there any additional configuration needed in the React Native app to fully encrypt data for each SmartStore soup? Below is the screenshot of the code on how to register the soup.

wmathurin commented 1 month ago

SmartStore uses SQLCipher as its database which takes care of encrypting all the data at rest.

For more information on local data encryption in Mobile SDK see https://help.salesforce.com/s/articleView?id=sf.mobile_security_local_data.htm&type=5

The documentation talks about Salesforce Mobile App (which uses Salesforce Mobile SDK for its local data storage and encryption).

For more information on SQLCipher see https://www.zetetic.net/sqlcipher/

mingfeng-alphline commented 1 month ago

I ran through the SalesForce Mobile SDK - React Native code and didn't find any encryption method. Based on my understanding of the SDK - React Native is called the native module from the SalesForce Mobile SDK - Android/ iOS, but there are no methods called the smartstore encryption function.

Question

  1. Is all data within SmartStore soups encrypted automatically, or are there certain data types or fields that require manual encryption?

  2. Is the encryption applied to SmartStore soups, both global and user stores?

wmathurin commented 4 weeks ago

We do have encryption methods and classes - we used them for encrypting files and other sensitive data like oauth tokens. The most sensitive data is stored using whatever the platform offers (e.g. secure enclave on iOS). If you look at the SmartStore code, you should see the code where we generate the encryption key and pass it to SQLCipher. All data in SmartStore is encrypted at rest (it does not matter if it is global or user store).

You might have been looking in the wrong place? You won't find any of the relevant code in this repo.

For the Mobile SDK side check out:

If you want to see how SQLCipher does it:

mingfeng-alphline commented 3 weeks ago

Thanks for the info!!

We managed to drill down to the SalesforceMobileSDK-iOS, and we found the error "no such function: sqlchiper_export in "SELECT sqlcipher_export('encryted')" and causing the smartstore not being encrypted

Do you have any idea to fix on it?

wmathurin commented 3 weeks ago

Can you give us more details? How did you execute that call?

mingfeng-alphline commented 3 weeks ago

When we debug the Salesforce Mobile SDK iOS, then the 355 lines of code (Figure 1) will prompt the error “no such function: sqlcipher_export in “SELECT sqlcipher_export(‘encrypted’)” (Figure 2).

According to our research, the sqlcipher_export function belongs to the SQL Cipher library, which is supposed to encrypt the SmartStore. So, we assume this error is related to the smartstore not being encrypted.

Figure 1: SF Smartstore Database Manager Code image

Figure 2: Error message from SmartStore image

We are unable to share the details of the un-encrypted file on this public platform as they are confidential, but can share it with your SF team in a meeting or in another private manner.

Below is the testing methodology conducted during the penetration testing:

Prerequisites:

Testing Methodology:

  1. Install iMazing on host system. iMazing will be used to browse the iPad 7th generation file system
  2. Setup the testing device: 2.1. Jailbreak the iPad 7th Generation (includes installing Sileo and packages inside Sileo such as Frida, Ellekit, PreferenceLoader, openssh) 2.2. Install the decrypted IPA file (Company QA mobile app)
  3. Use the mobile application for some time to generate data in storage
  4. Browse to the location of 'store.sqlite' and copy the database file to host system
  5. Use tools like sqlitebrowser to the open 'store.sqlite' copied to host system
wmathurin commented 3 weeks ago

I just tried - I don't see that error. I generated a Mobile SDK application using forceios createwithtemplate --templaterepouri=MobileSyncExplorerSwift. Then I ran in / logged in and checked the log to see if SmartStore initialization gave the same error. But it did not.

CLASS: SFSmartStore initWithName:user:isGlobal: defaultStore, user: 00DB0000000ToZ3MAK-005B0000005V71XIAS-(null), isGlobal: 0
CLASS: SFSmartStoreDatabaseManager DB for store 'defaultStore' is unencrypted. Encrypting.
CLASS: SFSmartStore createSoupIndexTableSql: CREATE TABLE IF NOT EXISTS soup_index_map (soupName TEXT, path TEXT, columnName TEXT, columnType TEXT )
CLASS: SFSmartStore createSoupNamesTableSql: CREATE TABLE IF NOT EXISTS soup_attrs (id INTEGER PRIMARY KEY AUTOINCREMENT, soupName TEXT )
CLASS: SFSmartStore createSoupNamesIndexSql: CREATE INDEX soup_attrs_0 on soup_attrs ( soupName )
CLASS: SFSmartStore createLongOperationsStatusTableSql: CREATE TABLE IF NOT EXISTS long_operations_status (id INTEGER PRIMARY KEY AUTOINCREMENT, type TEXT, details TEXT, status TEXT, created INTEGER, lastModified INTEGER )

How did you create your application? How is the Mobile SDK library dependencies brought in?

mingfeng-alphline commented 3 weeks ago

We have generated the react-native application with the "forcereact create" without any template. Besides that, we also tried to generate the native application with the "forceios create" without any template.

Both applications also encountered this error: "no such function: sqlchiper_export in "SELECT sqlcipher_export('encrypted'). "

XCode version: 16.0 macOS: 15.0.1

We are unable to share the details of the un-encrypted file on this public platform as they are confidential, but can share it with your SF team in a meeting or in another private manner.

wmathurin commented 3 weeks ago

sqlcipher_export should be present otherwise encryption cannot take place. I suspect an issue with your build. See https://discuss.zetetic.net/t/no-such-function-sqlcipher-export/5979/2

wmathurin commented 3 weeks ago

Are you sure that SQLCipher is still linked in or that all its functions are intact after the IPA manipulation that you have described?

wmathurin commented 3 weeks ago

Could you check the logs while running the unmodified application to see if you see the same error (sqlcipher_export missing)?

mingfeng-alphline commented 3 weeks ago

Hi @wmathurin,

These are the steps we have taken to create a new project:

  1. Create project using the steps in this link: https://developer.salesforce.com/docs/platform/mobile-sdk/guide/ios-new-force-project.html

  2. open testapp.xcworkspace with Xcode image

  3. Change signing account and bundle identifier image

  4. Change to custom login URL image

  5. Change Consumer Key image

  6. Run the project and found the error image

We are using the following version of Xcode and Simulator. May we know which version are you using when you try to reproduce the issue?

Please let us know if there is something we need to configure on our side as we have not touched any configuration in the SF SDK part since you have previously mentioned there are no additional steps required for the encryption. We have found a similar issue here: https://discuss.zetetic.net/t/ios-project-with-sqlcipher-and-pod-sqlite-dependency/6319 but the solution provided does not work on our side. Are there any updated instruction similar to what is found in this post for the SQLCipher 4.6.1?

Please let us know when you are available for a call to close this matter and if there’s a need to discuss any sensitive information as its of great urgency that we close it today.

mingfeng-alphline commented 3 weeks ago

Hi @wmathurin,

After further research, we have found a fix for the encryption, and the issue seems to be on the SF SDK side. We have discovered that the Salesforce Mobile SDK v12.0.1 for iOS uses “pod ‘FMDB’” but according to the FMDB documentation (https://github.com/ccgus/fmdb), the Podfile should be using the “pod ‘FMDB/SQLCipher’” instead to allow the FMDB to work together with the SQL Cipher.

image

After making the changes above, the encryption is working. Can we check if you have any concerns (i.e., functionality, security, etc.) regarding the approach that we have taken or have a fix to the original method that we can implement quickly?

Please also know your availability for a call on Monday we are based in SG Timezone.

wmathurin commented 3 weeks ago

The latest version of Mobile SDK (12.2) does not have the line above. Also it depends on FMDB 2.7.12 which has various fixes (including SQLCipher fixes). We recommend you use that version of Mobile SDK. Please give it a try and let us know if you have any issues.

mingfeng-alphline commented 2 weeks ago

Hi @wmathurin

If we were to upgrade to Mobile SDK 12.2, our current React Native and libraries would need to be upgraded, too. Due to the impacted libraries, this would potentially mean updating our source codes, which would throw up additional risks on our end. Can we stick to our alternative solution (as mentioned in the earlier comment), to replace the "FMDB" with "FMDB/SQLCipher" on the current Mobile SDK version 12.0.1 instead?

wmathurin commented 2 weeks ago

Yes, that should work.

mingfeng-alphline commented 2 weeks ago

Hi @wmathurin Can we check if you have any concerns (i.e., functionality, security, etc.) regarding the alternative approach to: " replace the "FMDB" with "FMDB/SQLCipher" on the current Mobile SDK version 12.0.1 instead"

wmathurin commented 2 weeks ago

SmartStore.podspec correctly depends on FMDB/SQLCipher. But when FMDB 2.7.10 came out, it was not immediately available on cocoapods and therefore we needed to add the git/tag pod dependency line in the app's Podfile. Unfortunately having pod 'FMDB' in the podfile and a dependency to 'FMDB/SQLCipher' in SmartStore.podspec did not lead to the FMDB+SQLCipher being linked into the application using the git/tag specified as one might expect but simply having FMDB+SQLite3 to be linked in. The issue went undetected because our internal apps have their own podfile and our tests run in the main repo where SQLCipher/FMDB are linked in without using SQLCipher.

You can actually drop that line entirely from the podfile and it will work also.

mingfeng-alphline commented 2 weeks ago

hi @wmathurin, thanks for the response. Can we also check what is the encryption method used for the Mobile SDK/SmartStore? Is it AES-CBC or AES-GCM? If it is AES-CBC, is there a way we can change it to AES-GCM?

wmathurin commented 2 weeks ago

SQLCipher uses 256-bit AES (CBC mode/PBKDF2 key derivation) - see https://www.zetetic.net/sqlcipher/design/. It cannot be changed.

Salesforce Mobile SDK also has a key value store which stores the values in individual encrypted files. That is using AES-GCM (since Mobile SDK 9.2). See https://developer.salesforce.com/docs/platform/mobile-sdk/guide/auth-secure-key-storage-ios.html?q=aes-gcm.