Home Mobile Secure Local Storage
Post
Cancel

Mobile Secure Local Storage

When developing iOS or Android apps, there’s a need to store some data locally, such as basic fetch data, usernames, and passwords. However, using standard storage methods like shared preferences on Android, Core Data and NSUserDefaults on iOS, or Async Storage in React Native may pose security risks. These traditional storage methods lack encryption, making the stored data susceptible to potential breaches, leading to unauthorized access or compromise on devices.

In this blog post, we will delve into techniques for secure local data storage, with a specific focus on Android and React Native.

Local Data Storage Techniques

Android Shared Preference

If you have a modest set of key-value pairs to store, consider leveraging the SharedPreferences APIs. These APIs allow you to create a SharedPreferences object, which points to a file holding key-value pairs and offers straightforward methods for reading and writing them. The framework manages each SharedPreferences file, allowing you to designate it as either private or shared.

1
2
3
4
5
SharedPreferences pref = getApplicationContext().getSharedPreferences("MyPref", 0);
Editor editor = pref.edit();

editor.putString("password", "s3cr3t"); // Storing string 
editor.commit(); // Commit changes

This code snippet writes key-value pairs to an XML file located at /data/data//shared_prefs.

Now, check the shared preference file, stored data is unencrypted xml data:

1
2
3
4
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="key_name">s3cr3t</string>
</map>

iOS NSUserDefaults

NSUserDefaults is a class in the iOS (and macOS) development framework that provides a simple interface for persistently storing small amounts of data. It’s commonly used for storing user preferences, settings, and other configuration information.

NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];

// Saving various data types
[prefs setObject:@"IT0809" forKey:@"AccessNo"];
[prefs setInteger:42 forKey:@"RollNo"];
[prefs setDouble:9.99 forKey:@"DoubleKey"];
[prefs setFloat:1.7565671 forKey:@"FloatKey"];
[prefs synchronize];

Data is stored in a .plist file in the ~/Library/Preferences/… folder.

React Native AsyncStorage

AsyncStorage is an asynchronous, persistent, key-value storage system. For Android, data is stored in SQLite, while for iOS, small values are serialized in a common manifest.json file, and larger values are stored in dedicated files.

1
2
3
4
5
6
7
const storeData = async (value) => {
  try {
    await AsyncStorage.setItem('my-key', value);
  } catch (e) {
    // saving error
  }
};

Securing Local Storage

Android Keystore

The Android Keystore system allows for the secure storage of cryptographic keys, with the keys stored in an environment inaccessible to the application. EncryptedSharedPreferences is a function that transparently encrypts and decrypts using the keychain master key when reading or writing shared preferences.

MasterKey masterKey = new MasterKey.Builder(context).setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build();
SharedPreferences sharedPreferences = EncryptedSharedPreferences.create(context, "secret_shared_prefs", masterKey, EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM);

iOS Keychain

The keychain services API provides a mechanism to store small encrypted user data. It allows secure storage of sensitive information like passwords.

React Native Security Libraries

Various React Native libraries implement secure storage for both iOS and Android:

Example using expo-secure-store to save a username and password:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import { StatusBar } from 'expo-status-bar';
import { Button, StyleSheet, Text, TextInput, View } from 'react-native';
import * as SecureStore from 'expo-secure-store';
import * as VersionCheck from 'react-native-version-check-expo'
import { useState } from 'react';


export default function App() {
  const [username, setUsername] = useState("")  
  const [password, setPassword] = useState("")
  const isShowPassword = true

  async function onRemember () {
    try {
      await SecureStore.setItemAsync("username", username)
      await SecureStore.setItemAsync("password", password)

      alert("Saved")
    } catch (e) {
      console.log(e)
    }
  }

  async function onLoadRemember () {
    try {
      const username = await SecureStore.getItemAsync('username')
      const password = await SecureStore.getItemAsync('password')
      setUsername(username)
      setPassword(password)
      
      alert("Loaded")
    } catch (e) {
      console.log(e)
    }
  }

  async function onReset() {
    setUsername("")
    setPassword("")
  }

  return (
    <View style={styles.container}>
      <Text style=>Login into app</Text>
      <TextInput onChangeText={setUsername} style={styles.input} placeholder='Username' value={username} />
      <TextInput onChangeText={setPassword} style={styles.input} placeholder='Password' value={password} secureTextEntry={!isShowPassword} />
      <Button onPress={onRemember} color={'#000000'} title='Remember'/>
      <Text> </Text>
      <Button onPress={onLoadRemember} color={'#000000'} title='Load Remember'/>
      <Text> </Text>
      <Button onPress={onReset} color={'#000000'} title='Reset'/>
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
  input: {
    height: 40,
    margin: 8,
    borderWidth: 1,
    padding: 10,
    width: 200
  },
});

Demo app

Enter username, password and press remember. Then, check the shared preference file:

1
2
3
4
5
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="password">{&quot;ct&quot;:&quot;mJr\/weUfpWSrK8yy8K31sGjeBDZlX7gIM5DRQjLRTH6f2A==&quot;,&quot;iv&quot;:&quot;U3oKZi4ic+wpoQ6u&quot;,&quot;tlen&quot;:128,&quot;scheme&quot;:&quot;aes&quot;}</string>
    <string name="username">{&quot;ct&quot;:&quot;PvfdYhUcY3mNAC3XTe6TtKX3S3K4BaMF&quot;,&quot;iv&quot;:&quot;I2SKVAlsQhTjF5zV&quot;,&quot;tlen&quot;:128,&quot;scheme&quot;:&quot;aes&quot;}</string>
</map>

By implementing secure storage solutions, developers can ensure the protection of sensitive local data against potential security threats and unauthorized access.

This post is licensed under CC BY 4.0 by the author.