Enhancing App Security in React Native: JailMonkey, Code Obfuscation, and Secure Storage

30 / Sep / 2024 by Ajmal Hasan 0 comments

In today’s digital age, securing mobile applications is a critical concern, especially when dealing with sensitive user data. With the rapid increase in threats such as reverse engineering and unauthorized data access, it becomes essential for developers to adopt effective strategies to protect their applications. In this blog, we will explore how to enhance security in React Native applications by leveraging tools like JailMonkey, implementing code obfuscation, and using secure storage solutions.

1. Detect Device Security Issues with JailMonkey

JailMonkey is a powerful React Native library designed to detect potential security threats on a user’s device. It provides checks to determine if the device is jailbroken (iOS) or rooted (Android), thus helping developers safeguard their apps against compromised devices.

Why Use JailMonkey?

Some applications, particularly those handling sensitive data, need to ensure they are running in secure environments. JailMonkey assists in identifying risks, ensuring your app is not running on a jailbroken or rooted device, which could expose it to data integrity threats.

Here’s what JailMonkey helps you achieve:

  • Identify Jailbroken or Rooted Devices for iOS and Android.
  • Detect Mock Locations, a feature often used in developer mode.
  • Detect External Storage Usage (Android only), where apps may be running on insecure external SD cards.

Installation:

yarn add jail-monkey
# or
npm install jail-monkey

Usage Example:

import JailMonkey from 'jail-monkey';
import RNExitApp from 'react-native-exit-app';

const checkJailMonkey = useCallback(() => {
  const isJailBroken = JailMonkey.isOnExternalStorage() || JailMonkey.isJailBroken();
  if (isJailBroken && !__DEV__) {
    Alert.alert(
      textString.securityWarning,
      textString.jailBrokenWarning,
      [{ text: 'OK', onPress: () => RNExitApp.exitApp() }],
      { cancelable: false }
    );
  }
}, []);

useEffect(() => {
  checkJailMonkey();
}, []);

This setup ensures that if a device is identified as compromised, the app will display a warning and exit, preventing further use in unsafe environments.

2. Strengthening Security with React Native Code Obfuscation

What is Code Obfuscation?

Code obfuscation is a technique used to transform code into a format that is difficult to read or understand. This adds an extra layer of protection to prevent reverse engineering and intellectual property theft. In React Native, code obfuscation can be applied to JavaScript as well as the native Android and iOS code.

2.1 Obfuscating React Native JavaScript Code

Obfuscating JavaScript in React Native can be achieved using the Metro Plugin. Here’s how to do it:

a) Install the Metro Plugin:
npm i -D obfuscator-io-metro-plugin
# or
yarn add -D obfuscator-io-metro-plugin
b) Modify metro.config.js:
const jsoMetroPlugin = require("obfuscator-io-metro-plugin")(
  {
    compact: false,
    sourceMap: false, 
    controlFlowFlattening: true,
    controlFlowFlatteningThreshold: 1,
    numbersToExpressions: true,
    simplify: true,
    stringArrayShuffle: true,
    splitStrings: true,
    stringArrayThreshold: 1,
  },
  {
    runInDev: false, 
    logObfuscatedFiles: true, 
  }
);

module.exports = {
  transformer: {
    getTransformOptions: async () => ({
      transform: {
        experimentalImportSupport: false,
        inlineRequires: false,
      },
    }),
  },
  ...jsoMetroPlugin, // Add this line to your Metro configuration
};

Note: Add .jso files to .gitignore to prevent them from being committed to version control.

2.2 Obfuscating Android Code

For Android, code obfuscation is achieved using R8. R8 allows for both code shrinking and obfuscation, thus reducing the app size while protecting the code.

a) Configure build.gradle:
def enableProguardInReleaseBuilds = true

buildTypes {
    release {
        debuggable false
        shrinkResources enableProguardInReleaseBuilds
        minifyEnabled enableProguardInReleaseBuilds
        proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
    }
}
b) Update proguard-rules.pro:
-keep class io.invertase.firebase.** { *; }
-dontwarn io.invertase.firebase.**

-keep class com.awrostamani.BuildConfig { *; }
-keep class com.swmansion.reanimated.** { *; }
-keep class com.facebook.react.turbomodule.** { *; }
-keep public class com.horcrux.svg.** {*;}

If your app crashes after enabling ProGuard, check Crashlytics for the problematic library and add appropriate rules in proguard-rules.pro.

2.3 Obfuscating iOS Code

Currently, there is no built-in library for obfuscating iOS code in React Native. However, you can explore external packages for this purpose as outlined in this StackOverflow thread.

3. Storing Sensitive Data Securely

Sensitive data such as tokens, user credentials, and other private information should be stored securely. React Native provides excellent libraries like MMKV and Keychain for this purpose.

Conclusion

Securing your React Native app is not just about implementing encryption or authentication mechanisms—it’s about a comprehensive approach that includes detecting compromised devices, obfuscating your code, and storing sensitive data securely. By utilizing tools like JailMonkey, applying code obfuscation techniques, and leveraging secure storage options like MMKV and Keychain, you can ensure your app remains protected from potential threats.

FOUND THIS USEFUL? SHARE IT

Leave a Reply

Your email address will not be published. Required fields are marked *