Save Sensitive Data in React Native

How to store sensitive data in React Native or expo code ? ( with Keychain and Keystore )

How to store sensitive data in React Native code?

The libraries

Now multiples libraries allow you to store sensitive in React Native code:

  • expo-secure-store
  • react-native-keychain
  • react-native-encrypted-storage

Note: On the native side, theses libraries can use:

  • Keychain for iOS
  • Android Keystore for Android
  • Encrypted Shared Preferences for Android

Example

Here is an example of usage with react-native-keychain to store sensitive data with react-native

For iOS it use Keychain Sharing Capabilities

For Android it use:

  • API level 16-22 use Facebook Conceal
  • API level 23+ use Android Keystore

You can use it like that:

// Generic Password, service argument optional
Keychain
.setGenericPassword(username, password)
.then(function() {
console.log('Credentials saved successfully!');
});

// service argument optional
Keychain
.getGenericPassword()
.then(function(credentials) {
console.log('Credentials successfully loaded for user ' + credentials.username);
}).catch(function(error) {
console.log('Keychain couldn\'t be accessed! Maybe no value set?', error);
});

Save sensitive data in React Native

Just digging into the React Native code, I found the answer.

Android

The React Native AsyncStoragemodule implementation is based on SQLiteOpenHelper.
The package where all the data classes are handled: https://github.com/facebook/react-native/tree/master/ReactAndroid/src/main/java/com/facebook/react/modules/storage

The class with the instructions to create the database: https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/modules/storage/ReactDatabaseSupplier.java

By the Android documentation, the databases created by the application are saved in private disk space that's associated application, so it is secure.

Just like files that you save on the device's internal storage,
Android stores your database in private disk space that's associated
application. Your data is secure, because by default this area is not
accessible to other applications.

Source

iOS

In iOS the AsyncStorage values are saved in serialized dictionary files. Those files are saved in the application NSDocumentDirectory. In iOS all applications live in their own sandbox, so all files of one application are secured, they cannot be accessed by the other applications.

The code in iOS that handles the AsyncStorage module can be found here: https://github.com/facebook/react-native/blob/master/React/Modules/RCTAsyncLocalStorage.m

And as we can see here the files used to store the values saved by the AsyncStorage are saved under the NSDocumentDirectory (inside the application sandbox environment).

Every App Is an Island An iOS app’s interactions with the file system
are limited mostly to the directories inside the app’s sandbox. During
installation of a new app, the installer creates a number of
containers for the app. Each container has a specific role. The bundle
container holds the app’s bundle, whereas the data container holds
data for both the application and the user. The data container is
further divided into a number of directories that the app can use to
sort and organize its data. The app may also request access to
additional containers—for example, the iCloud container—at runtime.

Source

Conclusion

It is safe to use AsyncStorage to save user tokens, since they are saved under a secure context.

Please note that this is only true for Android devices without root and for iOS devices without jailbreak. Please also note that if the attacker has physical access to the device and the device is not protected. He can connect the device to the mac laptop and extract the documents directory and see all the contents saved under the documents directory.

How secure sensitive data in react-native app

Exchanged one Problem with Another

In my application I have a connection with keycloak for get an API key and a secure storage to save the user data.

So, using KeyCloak to retrieve the API Key at runtime in order to not have it harcoded in the mobile app, just shifts the problem from securing the API key to securing the KeyCloak secret.

Extracting Secrets from the Mobile App

How I can secure :

  • the secret id need to connect to the keycloak
  • the key to access the secure store

The cruel truth is that you can't properly secure them, because any secret you ship in a mobile app release must be considered as belonging to the public domain, because it's on the client side, therefore anyone can spend the time he/she wants to reverse engineer the mobile app with static or dynamic analysis to extract it.

You can hide the secret in Natice C code with the use of JNI/NDK as I show in the article How to Extract an API key from a Mobile App with Static Binary Analysis:

The range of open source tools available for reverse engineering is huge, and we really can't scratch the surface of this topic in this article, but instead we will focus in using the Mobile Security Framework(MobSF) to demonstrate how to reverse engineer the APK of our mobile app. MobSF is a collection of open source tools that present their results in an attractive dashboard, but the same tools used under the hood within MobSF and elsewhere can be used individually to achieve the same results.

Now, with the secret hidden in the native C code it will be time consuming to extract it, but not impossible. So, if you cannot do it easily with statically reverse engineer it, then you can do it with a MitM attack as I show in the article Steal that Api Key with a Man in the Middle Attack:

In order to help to demonstrate how to steal an API key, I have built and released in Github the Currency Converter Demo app for Android, which uses the same JNI/NDK technique we used in the earlier Android Hide Secrets app to hide the API key.

So, in this article you will learn how to setup and run a MitM attack to intercept https traffic in a mobile device under your control, so that you can steal the API key. Finally, you will see at a high level how MitM attacks can be mitigated.

Do you get the the twist? You can make it very hard to extract with static binary analysis, but then the attacker just needs to use a tool like mitmproxy to intercept the traffic and lookup the API key in the header of the request.

You can try to safeguard your mobile app against MitM attacks has I exemplify in my article Securing HTTPS with Certificate Pinning:

In order to demonstrate how to use certificate pinning for protecting the https traffic between your mobile app and your API server, we will use the same Currency Converter Demo mobile app that I used in the previous article.

In this article we will learn what certificate pinning is, when to use it, how to implement it in an Android app, and how it can prevent a MitM attack.

But, you need to be aware that you can also bypass pinning as I show in the next article Bypass Certificate Pinning:

To demonstrate how to bypass certificate pinning we will use the same Currency Converter Demo mobile app that was used in the previous article.

In this article you will learn how to repackage a mobile app in order to make it trust custom ssl certificates. This will allow us to bypass certificate pinning.

Other alternative for the attacker is to use an instrumentation framework to hook into the code that returns the secret or API key from the keystore or from KeyCloak server. A popular instrumentation framework used for this type of attack is Frida:

Inject your own scripts into black box processes. Hook any function, spy on crypto APIs or trace private application code, no source code needed. Edit, hit save, and instantly see the results. All without compilation steps or program restarts.

So, the use of Frida to hookup in the code is made easier when the code is not obfuscated, because it's easy to find the function that does it by doing some search through the code with some guessable function names, or just resort to follow the code flow with the help of an IDE.

Code Obfuscation and it's importance

It's possible to obfuscate the code but it's not a serious solution and this has a great impact on performance.

Yes, you are right that code obfuscation will not hide the secret, only makes it hard to understand the logic flow.

Code obfuscation should still be in your list of security hardening your mobile app, and once used as Google recommends, by shrink code and resources, obfuscate, and optimize your app with R8, and then you will not have a slower app just because the code is obfuscated, but you will have one that is much harder to follow the logic through the code, thus an attacker poking around the code to find were to hook an instrumentation framework will have a much more consuming time task, to not call it frustrating sometimes.

Securing the Secrets in the Mobile App

I read different article but I didn't find a way to properly secure those data. A simple revert engineering from the APK show the secret data.

Yes, you cannot find one because that's not a trivial problem to solve, you can only make it hard, but not impossible.

The Difference Between WHO and WHAT is Accessing the API Server

Before I dive into the possible approaches to solve your problem I would like to first clear a misconception that usually I find among developers of any seniority, that is about the difference between who and what is accessing an API server.

I wrote a series of articles around API and Mobile security, and in the article Why Does Your Mobile App Need An Api Key? you can read in detail the difference between who and what is accessing your API server, but I will extract here the main takes from it:

The what is the thing making the request to the API server. Is it really a genuine instance of your mobile app, or is it a bot, an automated script or an attacker manually poking around your API server with a tool like Postman?

The who is the user of the mobile app that we can authenticate, authorize and identify in several ways, like using OpenID Connect or OAUTH2 flows.

So think about the who as the user your API server will be able to Authenticate and Authorize access to the data, and think about the what as the software making that request in behalf of the user.

Now that you are better informed about the difference between them you can make better informed decisions in terms of security and trade-offs when deciding waht approaches to take for your use case.

A Possible Naive Approach

  • Hide your API Key or if you prefer the KeyCloak secret in Native C Code as I show in the article I linked above that references this Github repo. This makes static reverse engineer the secret harder.
  • Shrink code and resources, obfuscate, and optimize your app as per Google instructions.This makes it hard to find the code were to hook Frida.
  • Implement certificate pinning. This makes it harder to perform a MitM attack.

I call it naive approach, because has I shown in my series of articles I linked it can be bypassed, but it raises the bar for the skill set and time necessary to do it.

A Possible Better Solution

So, your main goal seems to be to protect the API key, that you need to use as a way to identify your mobile app with the backend API server, aka to lock down the backend API server with the genuine and untampered versions of your mobile app, that will allow for the server to only answer to requests from the same binary that you uploaded to Google Play store, then you may want to take a look into the Mobile App Attestation concept, and to for that I recommend you to read this answer I gave to the question How to secure an API REST for mobile app?, especially the sections Securing the API Server and A Possible Better Solution.

In a nutshell the role of a Mobile App Attestation solution is to guarantee at run-time that your mobile app was not tampered with, is not running in a rooted device, not being instrumented by a framework like xPosed or Frida, not being MitM attacked, and this is achieved by running an SDK in the background. The service running in the cloud will challenge the app, and based on the responses it will attest the integrity of the mobile app and device is running on, thus the SDK will never be responsible for any decisions.

Do You Want To Go The Extra Mile?

In any response to a security question I always like to reference the excellent work from the OWASP foundation.

For APIS

OWASP API Security Top 10

The OWASP API Security Project seeks to provide value to software developers and security assessors by underscoring the potential risks in insecure APIs, and illustrating how these risks may be mitigated. In order to facilitate this goal, the OWASP API Security Project will create and maintain a Top 10 API Security Risks document, as well as a documentation portal for best practices when creating or assessing APIs.

For Mobile Apps

OWASP Mobile Security Project - Top 10 risks

The OWASP Mobile Security Project is a centralized resource intended to give developers and security teams the resources they need to build and maintain secure mobile applications. Through the project, our goal is to classify mobile security risks and provide developmental controls to reduce their impact or likelihood of exploitation.

OWASP - Mobile Security Testing Guide:

The Mobile Security Testing Guide (MSTG) is a comprehensive manual for mobile app security development, testing and reverse engineering.

How to store sensitive data in react js frontend?

Normally sensitive data are not saving on frontend.
best way is you can call this from server using http request.
Or you can use local storage,cookies,session storage etc.
env setup is another way.
Or you can use thirdparty storge for this, many free & trusted resources are available

How to save data in react-native

You can take this lib as more popular.

For example code:

import AsyncStorage from '@react-native-async-storage/async-storage';

await AsyncStorage.setItem(key, value);

const value = await AsyncStorage.getItem(key);
console.log('MY_VALUE===>', value);

await AsyncStorage.removeItem(key);

I hope, it is help you.

How to properly save sensitive data on frontend using next.js?

Following the answers, I created a useContext to use in any component that I need.

Here is what I have in my context:

const [userRoles, setUserRoles] = useState<string[] | undefined>([])

const getUsersRoles = useCallback(async () => {
const getUserRoles = await UsersService.getUsersRoles(userInfo.idUsuario)
setUserRoles(getUserRoles.data)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])

Note: UsersService.getUsersRoles function is integration with the API

And how I use it in the component I need:

const { userRoles, getUsersRoles } = useAuth()

if (userRoles?.length === 0) {
getUsersRoles()
return <LoadingGIf tip="Carregando opções..." />
}

With this, I have the data I need here userRoles. And IF the user reload/refresh the page, getUsersRoles is requested and set the data to the userRoles

The downside to this, at least for me, is that I have to add this:

const { userRoles, getUsersRoles } = useAuth()

if (userRoles?.length === 0) {
getUsersRoles()
return <LoadingGIf tip="Carregando opções..." />
}

for every component I need to use the roles data, but I believe that's it. It's working fine and isn't request extra any endpoints of API.

If anyone has a contribuitions or improves to do in the code, fell free to do it.



Related Topics



Leave a reply



Submit