Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
45 views

Data Storage On Android

This document discusses data storage on Android and provides best practices. It covers various data storage methods like SharedPreferences, SQLite databases, and Firebase databases. The document stresses that sensitive data should be protected and not stored in plaintext or made world readable. It provides examples of improperly storing credentials in SharedPreferences and an unencrypted SQLite database.

Uploaded by

1932 Parekh Jeel
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
45 views

Data Storage On Android

This document discusses data storage on Android and provides best practices. It covers various data storage methods like SharedPreferences, SQLite databases, and Firebase databases. The document stresses that sensitive data should be protected and not stored in plaintext or made world readable. It provides examples of improperly storing credentials in SharedPreferences and an unencrypted SQLite database.

Uploaded by

1932 Parekh Jeel
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 10

Data Storage on Android

Protecting authentication tokens, private information, and other sensitive data is key
to mobile security. In this chapter, you will learn about the APIs Android offers for
local data storage and best practices for using them.

The guidelines for saving data can be summarized quite easily: Public data should
be available to everyone, but sensitive and private data must be protected, or, better
yet, kept out of device storage.

This chapter is broken into two sections, the first of which focuses on the theory of
data storage from a security perspective as well as a brief explanation and example
of the various methods of data storage on Android.

The second section focuses on the testing of these data storage solutions through
the usage of test cases that utilize both static and dynamic analysis.

Theory Overview
​ Storing data is essential to many mobile apps. Conventional wisdom suggests
that as little sensitive data as possible should be stored on permanent local storage.
In most practical scenarios, however, some type of user data must be stored. For
example, asking the user to enter a very complex password every time the app starts
isn't a great idea in terms of usability. Most apps must locally cache some kind of
authentication token to avoid this. Personally identifiable information (PII) and other
types of sensitive data may also be saved if a given scenario calls for it.

Sensitive data is vulnerable when it is not properly protected by the app that is
persistently storing it. The app may be able to store the data in several places, for
example, on the device or on an external SD card. When you're trying to exploit these
kinds of issues, consider that a lot of information may be processed and stored in
different locations.

First, it is important to identify the kind of information processed by the mobile


application and input by the user. Next, determining what can be considered
sensitive data that may be valuable to attackers (e.g., passwords, credit card
information, PII) is not always a trivial task and it strongly depends on the context of
the target application. You can find more details regarding data classification in the
"Identifying Sensitive Data" section of the chapter "Mobile App Security Testing". For
general information on Android Data Storage Security, refer to the Security Tips for
Storing Data in the Android developer's guide.
Disclosing sensitive information has several consequences, including decrypted
information. In general, an attacker may identify this information and use it for
additional attacks, such as social engineering (if PII has been disclosed), account
hijacking (if session information or an authentication token has been disclosed), and
gathering information from apps that have a payment option (to attack and abuse
them).

Next to protecting sensitive data, you need to ensure that data read from any storage
source is validated and possibly sanitized. The validation usually ranges from
checking for the correct data types to using additional cryptographic controls, such
as an HMAC, you can validate the integrity of the data.

Data Storage Methods Overview


Android provides a number of methods for data storage depending on the needs of
the user, developer, and application. For example, some apps use data storage to
keep track of user settings or user-provided data. Data can be stored persistently for
this use case in several ways. The following list of persistent storage techniques are
widely used on the Android platform:

 Shared Preferences
 SQLite Databases
 Firebase Databases
 Realm Databases
 Internal Storage
 External Storage
 Keystore
In addition to this, there are a number of other functions in Android built for various
use cases that can also result in the storage of data and respectively should also be
tested, such as:

 Logging Functions
 Android Backups
 Processes Memory
 Keyboard Caches
 Screenshots
It is important to understand each relevant data storage function in order to correctly
perform the appropriate test cases. This overview aims to provide a brief outline of
each of these data storage methods, as well as point testers to further relevant
documentation.

Shared Preferences
The SharedPreferences API is commonly used to permanently save small collections
of key-value pairs. Data stored in a SharedPreferences object is written to a plain-text
XML file. The SharedPreferences object can be declared world-readable (accessible
to all apps) or private. Misuse of the SharedPreferences API can often lead to
exposure of sensitive data. Consider the following example:

Example for Java:

SharedPreferences sharedPref = getSharedPreferences("key",


MODE_WORLD_READABLE);

SharedPreferences.Editor editor = sharedPref.edit();

editor.putString("username", "administrator");

editor.putString("password", "supersecret");

editor.commit();

Example for Kotlin:

var sharedPref = getSharedPreferences("key", Context.MODE_WORLD_READABLE)

var editor = sharedPref.edit()

editor.putString("username", "administrator")

editor.putString("password", "supersecret")

editor.commit()

Once the activity has been called, the file key.xml will be created with the provided
data. This code violates several best practices.

 The username and password are stored in clear text in /data/data/<package-


name>/shared_prefs/key.xml.
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>

<map>

<string name="username">administrator</string>

<string name="password">supersecret</string>

</map>

 MODE_WORLD_READABLE allows all applications to access and read the


contents of key.xml.

root@hermes:/data/data/sg.vp.owasp_mobile.myfirstapp/shared_prefs # ls -la

-rw-rw-r-- u0_a118 170 2016-04-23 16:51 key.xml

Please note that MODE_WORLD_READABLE and MODE_WORLD_WRITEABLE were


deprecated starting on API level 17. Although newer devices may not be affected by
this, applications compiled with an android:targetSdkVersion value less than 17 may
be affected if they run on an OS version that was released before Android 4.2 (API
level 17).

Databases

The Android platform provides a number of database options as aforementioned in


the previous list. Each database option has its own quirks and methods that need to
be understood.

SQLite Database (Unencrypted)

SQLite is an SQL database engine that stores data in .db files. The Android SDK has
built-in support for SQLite databases. The main package used to manage the
databases is android.database.sqlite. For example, you may use the following code to
store sensitive information within an activity:
Example in Java:
SQLiteDatabase notSoSecure = openOrCreateDatabase("privateNotSoSecure",
MODE_PRIVATE, null);

notSoSecure.execSQL("CREATE TABLE IF NOT EXISTS Accounts(Username


VARCHAR, Password VARCHAR);");

notSoSecure.execSQL("INSERT INTO Accounts VALUES('admin','AdminPass');");

notSoSecure.close();

Example in Kotlin:

var notSoSecure = openOrCreateDatabase("privateNotSoSecure",


Context.MODE_PRIVATE, null)

notSoSecure.execSQL("CREATE TABLE IF NOT EXISTS Accounts(Username


VARCHAR, Password VARCHAR);")

notSoSecure.execSQL("INSERT INTO Accounts VALUES('admin','AdminPass');")

notSoSecure.close()

Once the activity has been called, the database file privateNotSoSecure will be created
with the provided data and stored in the clear text file /data/data/<package-
name>/databases/privateNotSoSecure.
The database's directory may contain several files besides the SQLite database:

 ​ Journal files: These are temporary files used to implement atomic commit
and rollback.
 ​ Lock files: The lock files are part of the locking and journaling feature,
which was designed to improve SQLite concurrency and reduce the writer
starvation problem.
Sensitive information should not be stored in unencrypted SQLite databases.

SQLite Databases (Encrypted)

With the library SQLCipher, SQLite databases can be password-encrypted.


Example in Java:

SQLiteDatabase secureDB = SQLiteDatabase.openOrCreateDatabase(database,


"password123", null);

secureDB.execSQL("CREATE TABLE IF NOT EXISTS Accounts(Username


VARCHAR,Password VARCHAR);");

secureDB.execSQL("INSERT INTO Accounts VALUES('admin','AdminPassEnc');");

secureDB.close();

Example in Kotlin:

var secureDB = SQLiteDatabase.openOrCreateDatabase(database, "password123",


null)

secureDB.execSQL("CREATE TABLE IF NOT EXISTS Accounts(Username


VARCHAR,Password VARCHAR);")

secureDB.execSQL("INSERT INTO Accounts VALUES('admin','AdminPassEnc');")

secureDB.close()

Secure ways to retrieve the database key include:

 Asking the user to decrypt the database with a PIN or password once the app
is opened (weak passwords and PINs are vulnerable to brute force attacks)
 Storing the key on the server and allowing it to be accessed from a web
service only (so that the app can be used only when the device is online)

Firebase Real-time Databases

Firebase is a development platform with more than 15 products, and one of them is
Firebase Real-time Database. It can be leveraged by application developers to store
and sync data with a NoSQL cloud-hosted database. The data is stored as JSON and
is synchronized in real-time to every connected client and also remains available
even when the application goes offline.

A misconfigured Firebase instance can be identified by making the following


network call:

https://_firebaseProjectName_.firebaseio.com/.json
The firebaseProjectName can be retrieved from the mobile application by reverse
engineering the application. Alternatively, the analysts can use Firebase Scanner, a
python script that automates the task above as shown below:

python FirebaseScanner.py -p <pathOfAPKFile>

python FirebaseScanner.py -f <commaSeperatedFirebaseProjectNames>

Realm Databases

The Realm Database for Java is becoming more and more popular among
developers. The database and its contents can be encrypted with a key stored in the
configuration file.

//the getKey() method either gets the key from the server or from a KeyStore, or
is derived from a password.

RealmConfiguration config = new RealmConfiguration.Builder()

.encryptionKey(getKey())

.build();

Realm realm = Realm.getInstance(config);

If the database is not encrypted, you should be able to obtain the data. If the
database is encrypted, determine whether the key is hard-coded in the source or
resources and whether it is stored unprotected in shared preferences or some other
location.

Internal Storage

You can save files to the device's internal storage. Files saved to internal storage are
containerized by default and cannot be accessed by other apps on the device. When
the user uninstalls your app, these files are removed. The following code snippets
would persistently store sensitive data to internal storage.

Example for Java:

FileOutputStream fos = null;

try {

fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);

fos.write(test.getBytes());

fos.close();

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

Example for Kotlin:

var fos: FileOutputStream? = null


fos = openFileOutput("FILENAME", Context.MODE_PRIVATE)

fos.write(test.toByteArray(Charsets.UTF_8))

fos.close()

You should check the file mode to make sure that only the app can access the file.
You can set this access with MODE_PRIVATE. Modes such as
MODE_WORLD_READABLE (deprecated) and MODE_WORLD_WRITEABLE (deprecated)
may pose a security risk.
Search for the class FileInputStream to find out which files are opened and read
within the app.

External Storage

Every Android-compatible device supports shared external storage. This storage


may be removable (such as an SD card) or internal (non-removable). Files saved to
external storage are world-readable. The user can modify them when USB mass
storage is enabled. You can use the following code snippets to persistently store
sensitive information to external storage as the contents of the file password.txt.
Example for Java:

File file = new File (Environment.getExternalFilesDir(), "password.txt");

String password = "SecretPassword";

FileOutputStream fos;

fos = new FileOutputStream(file);

fos.write(password.getBytes());

fos.close();

Example for Kotlin:


val password = "SecretPassword"

val path = context.getExternalFilesDir(null)

val file = File(path, "password.txt")

file.appendText(password)

The file will be created and the data will be stored in a clear text file in external
storage once the activity has been called.

It's also worth knowing that files stored outside the application folder
(data/data/<package-name>/) will not be deleted when the user uninstalls the
application. Finally, it's worth noting that the external storage can be used by an
attacker to allow for arbitrary control of the application in some cases. For more
information: see the blog from Checkpoint.

You might also like