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
AsyncStorage
module 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
Android - Inner Element Must Either Be a Resource Reference or Empty
How to Import Android Studio Project in Eclipse
Android String.Xml Reading HTML Tags Problem
How to Include Data Files with the App's APK
How to Display Menu Item with Icon and Text in Appcompatactivity
Preferencefragmentcompat Has Padding on Preferencecategory That I Can't Get Rid Of
How to Keep the Aspect Ratio on Image Buttons in Android
Add Onclick Listener to Predefined Button
Run-As Package 'A.B.C' Is Unknown - Galaxy S4 Jellybean or Android 4.3
Android Ndk: Link Using a Pre-Compiled Static Library
How to Retrieve a List Object from the Firebase in Android
Android - Receiving Long Sms (Multipart)
Use Recyclerview Inside Scrollview with Flexible Recycler Item Height