Securing React Native Application from Vulnerability & Penetration attacks

Imdad Hussain
8 min readJul 15, 2021

--

We are going to look into ways by which we can secure React Native application according to Vulnerability Assessment and Penetration Testing(VAPT).

Main points to look for security

  • Screenshot Prevention
  • Rooted/ Jailbroken Device Detection
  • SSL Pinning
  • Storage of Sensitive Data — API EndPoint / FB / Google / Firebase Keys
  • Local Storage
  • Deep Linking
  • Android Specific Security
  • iOS Specific Security
  • Authentication Methods
  • Data Encryption

1. Screenshot Prevention

Unfortunately, it’s almost impossible to prevent screenshot-taking on iOS devices. There is no simple or efficient solution. You can only get information AFTER taking a screenshot and display some information or pop-up to the user. But we still have some workarounds.

There are basically two ways to prevent users from taking screenshot. Neither is good in terms of performance and battery drain.

The first one is to create an invisible 60 fps animation on top of the “secured” screen. Because the iOS screenshot feature only saves a single frame, it would only capture the overlaid animation, but no the content you wish to hide.

The second one is paying for ScreenShieldKit, which is probably a variation of the solution described above.

Below code is for first solution. I know you are not going to pay for ScreenShieldKit.

For iOS

As I have mentioned screenshot restriction is not possible on Straight Forward Way, But you can do something like, When application InActive — add Blur Layer/ View on window and when Active — remove BlurLayer/View.

Add Following Lines of Code in AppDelegate.m

For Android

AS expected it’s quite simple to restrict user to prevent taking screenshot in Android.

Method 1: Go to MainActivity.java and add following code into it.

Method 2: Go to MainActivity.java, In onCreate method add this line

getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);

inside MainActivity.java

Thant’s It for Screenshot prevention.

2. Rooted/ Jailbroken Device Detection

Unlike other operating systems like Windows, Linux, or OSX, both Android and iOS operating systems are usually shipped with built-in user rights restrictions. The process of removing such restrictions, which is not supported by either Google or Apple, is named rooting and jailbreaking, respectively for Android and iOS.

In a rooted or jailbroken device, applications can have much more privileges than they should have. This means that malware will also be able to do things it would never be able to do in a non-modified device and may be hard or close to impossible to remove.

A root malware for instance can use a library like Xposed on Android to intercept the calls to the SSL libraries from a banking or payment application and read the confidential data transferred to financial institutions. Less obvious is that malware can root the operating system themselves and therefore a rooted device can be a sign of infection.

To protect against the risks posed by rooted/jailbroken devices, banking apps or other apps with sensitive data need the ability to detect such conditions and to respond to them by preventing the execution or restricting the functionalities of the application.

We are going to look for methods by which we will restrict our app to run on rooted/jailbroken devices.

For Android

Install this npm package.

You can look for rooted/jailbroken on start of application like in splash screen.

import the package at top of splash screen/(or any starting screen)

import JailMonkey from ‘jail-monkey’;
//then check inside componentDidMount
if (JailMonkey.isJailBroken()) {
this.setState({
show_proceed_modal: true
})
}

For iOS

I have found any good npm package that can detect rooted device. There is an option to make changes inside iOS native code ( I have not tried that too). After searching for solutions, I have got to know rooted device on iOS some files and we can look for them.
First check if Platform is iOS

if (Platform.OS == ‘ios’) {
this.checkIfFileExists()
}

We are calling a function checkIfFileExists(), Let’s find out what that function does

we are looking for specific files and showing same display modal. That we used for Android. That modal can be like this ( or you can just show an alert) But remember, you have to restrict the user so he/she won’t proceed further.

Modal

Ninja tip, you can exit the application on close press and only close button is clickable. :)

That’s It for for rooted/jailbroken device detection.

3. SSL Pinning

Securing mobile applications with Cert Pinning is a security process wherein a web application developer clearly defines specific certificates, to secure communications made by a mobile user, while using an application. It is essential to protect and defend the connection made from the request to the backend server, and this is where encryption security and HTTPS comes in the picture.

Advantages:

  • Reduces threat of a rogue Certificate Authority (CA)
  • Increase in-app data security and user privacy
  • Budget-friendly
  • Hackers need to increase resource cost to attack mobile app
  • Reduces exposure of eavesdropping and user device malware
  • Reports Man-In-Middle Attack (MITM) attacks and analyses them

SLL Pinning can be done using 3 different ways

  • Public Key Pinning
  • Certificate Pinning
  • Subject Public Key Info (SPKI) Pinning

iOS Integration: Place your .cer files in your iOS Project. Don’t forget to add them in your Build Phases — Copy Bundle Resources, in Xcode

Android Integration: Place your .cer files under src/main/assets/

You have to use this package, please read its documentation for generating certificates.

your fetch will look like this

That’s it for SSL pinning. You can follow doc of react-native-ssl-pinning docs for public key pinning.

4. Storage of Sensitive Data — API EndPoint / FB / Google / Firebase Keys

You should not store your API EndPoints and keys inside in code. I would recommend to use

and

to place your endpoints and and other import keys.
Why we need to do this? Because your bundle can be decoded into plaintext and all information can be extracted.

5. Local Storage

If you prefer to store data inside Asyncstorage, remember Asyncstorage is un-encrypted storage, so information can be extracted from it.

React Native does not provide solution for secure data storage. There are pre-existing solution in iOS & Android we all know about iOS Keychain and Android Keystore.
I have used react-native-sensitive-info that manages all data stored in Android Shared Preferences, iOS Keychain and Windows Credentials. You can set and get all key/value using almost same Asyncstorage methods.

6. Deep Linking

Deep linking is used to open application from other sources (website or other application). It looks like

appname://

that contains textual data within link. It can open specific page on your application. Let’s say you want to open a product detail page that has ID 123abc. Your deep link will be something like this.

appname://products/123abc

you can see we are exposing our product id inside deep link. One way to prevent exposure of product id is to wrap your deep link with another url service that can be https://bitly.com/ or https://www.shorturl.at/
In this way public deep link will not show product id.
Also note deep links are not secure and you should not append any sensitive information in deep link.

There is no centralised method of registering URL schemes. As developer, you can use any URL scheme you choose by configuring it in Xcode for iOS or adding an intent on Android.

Malicious app can hijack your data by also using the same scheme and then obtaining access to the data your link contains. Sending something like appname://products/1 is not harmful, but sending tokens is a security concern. iOS won’t check for unique URL Scheme while registering for it. That means same URL Scheme can be used for some malicious apps that will take advantage and compromise users.

Solution for these security issues can be:

Apple introduced Universal Links in iOS 9 as a solution to the lack of graceful fallback functionality in custom URI scheme deep links. Universal Links are standard web links that point to both a web page and a piece of content inside an app.

When a Universal Link is opened, iOS checks to see if any installed app is registered for that domain. If so, the app is launched immediately without ever loading the web page. If not, the web URL (which can be a simple redirect to the App Store) is loaded in Safari.

Setting up a universal link (HTTP or HTTPS) login interface, and musing a random identifier to authenticate the received login token locally, prevents hijacking and malicious login token replaying.

7. Android Specific Security (Protecting APK or app bundle)

You should protect APK or app bundle from reverse engineering attacks.

Hackers can easily access our Codebase by doing reverse engineering with APK or app bundle file. To avoid it we can add Pro Guard rules. Pro Guard obfuscates your code. So if someone reverse engineer it, it’s not readable and saves you from engineering attacks. Pro Guard also used to reduces APK size by removing unused code and resources. If your project contain any third party library then you can add the Pro Guard rules of that library in your rules file.

To enable Pro Guard rule we have to enable the minifyEnabled property in app/build.gradle file.

buildTypes {
release: {
minifyEnabled true
}
}

NOTE: It is not trick for complete avoidance of reverse engineering. You can look for others too.

8. iOS Specific Security

Let’s see how we can restrict the insecure domains usage in iOS. It will save us from transport layer attacks. You can restrict insecure domains by configuring some properties within your Info.plist file.

Now, let’s see what you should add in your Info.plist file for that.

From iOS 9.0 Apple has introduced NSAppTransportSecurity which you can find inside info.plist file. Inside NSAppTransportSecurity there is one key NSAllowArbitraryLoads which is set to NO by default that means you are agreed with security benefits. In some cases while you are working with localhost or with HTTP domain if required then you have to make it YES otherwise you can’t make network request with those insecure domains.

There are chances that your app might get rejected while uploading it to apple store because you set NSAllowArbitraryLoads value as YES. To overcome that you can use NSExceptionDomains by providing a list of domains inside that. Application will consider like you have agreed to all over security benefits excepts the domain those domains which you have mentioned in NSExceptionDomains (although you have set NSAllowArbitraryLoads value as YES).

<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>

9. Authentication Methods

Nowadays OAuth has become more popular for Authentication between one application interacting with another application. Consider a case where your application communicates with an API to send/retrieve data from the server. How do servers know the coming request is authenticated? OAuth 2.0 makes the authentication process simple for you. Instead of sharing passwords OAuth allows authentication using Token. It’s an approach to use JWT Token for API Authentication.

10. Data Encryption

Crypto JS is popular Javascript library for crypto standards. To store, send data to server it’s approached to Encrypt data using CrytpJS. So, it’s is not readable by enable directly.

Thanks for reading. Let me know if I missed any check or if you are facing any issue while implementing.

--

--

Imdad Hussain

Mobile Engineer @ Nova, React | React Native|Redux, JavaScript | TypeScript mostly Frontend | more at https://hussainimdad.web.app/