Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions best-practices/MASTG-BEST-0050.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
title: Store Data Encrypted in App Sandbox Directory
alias: store-data-encrypted-in-the-app-sandbox-directory
id: MASTG-BEST-0050
platform: android
knowledge: [MASTG-KNOW-0036]
---

Store sensitive data in `SharedPreferences` only after encrypting it. Standard `SharedPreferences` stores values in XML files inside the app's private data directory, so values such as credentials, authentication tokens, private keys, or personally identifiable information (PII) should not be stored in cleartext.

For apps that use `SharedPreferences`, use [`EncryptedSharedPreferences`](https://developer.android.com/reference/androidx/security/crypto/EncryptedSharedPreferences) or an equivalent mechanism that encrypts preference keys and values before they are written to disk. An equivalent mechanism should use authenticated encryption, protect encryption keys with the Android Keystore or another appropriate key management system, and avoid custom cryptography.

!!! note
`EncryptedSharedPreferences` is part of the Jetpack Security Crypto library. All APIs in that library were [deprecated](https://developer.android.com/privacy-and-security/cryptography#security-crypto-jetpack-deprecated) in version `1.1.0`, and Android states that there will be no subsequent releases. It may still be a practical mitigation for existing apps that must keep using `SharedPreferences`, but it should not be treated as a long term storage strategy. Monitor Android's cryptography and DataStore guidance, and plan a migration to a supported encryption approach when available.

Android recommends [`DataStore`](https://developer.android.com/topic/libraries/architecture/datastore) as a modern replacement for `SharedPreferences`, but `DataStore` does not encrypt data by default. If you migrate sensitive data to `DataStore`, use an appropriate encryption layer before writing the data. AndroidX introduced the `androidx.datastore:datastore-tink` artifact for DataStore encryption support in version `1.3.0-alpha07`. This provides encryption using the Tink library and [`AeadSerializer`](https://developer.android.com/reference/kotlin/androidx/datastore/tink/AeadSerializer), which wraps an existing DataStore serializer and performs authenticated encryption and decryption. See the [DataStore release notes](https://developer.android.com/jetpack/androidx/releases/datastore#1.3.0-alpha07) for more information and an example of use.
17 changes: 11 additions & 6 deletions demos/android/MASVS-STORAGE/MASTG-DEMO-0059/MASTG-DEMO-0059.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,37 @@ platform: android
title: Using SharedPreferences to Write Sensitive Data Unencrypted to the App Sandbox
id: MASTG-DEMO-0059
code: [kotlin]
test: MASTG-TEST-0207
test: MASTG-TEST-0287
Comment thread
cpholguera marked this conversation as resolved.
kind: fail
---

## Sample

The code below stores sensitive data using the `SharedPreferences` API, both with and without encryption:
The sample app stores sensitive data in `SharedPreferences`, which writes XML files inside the app's private sandbox storage.

Under normal Android sandboxing, other apps cannot directly read these files. However, if the app data directory becomes accessible, for example on a rooted or compromised device or through backup extraction, any unencrypted values stored in these XML files can be read directly.

The app stores the following sensitive data using the `SharedPreferences` API, both with and without encryption:

- An AWS key is stored encrypted
- A GitHub token is stored unencrypted
- A set of binary pre-shared keys is stored unencrypted
- A set of PEM-encoded private keys is stored unencrypted

When encryption is performed, it uses a securely generated key stored in the Android KeyStore.

{{ MastgTest.kt }}

When executing the code, you will be able to inspect the shared preferences file created in the app sandbox. For example, run the following command:
On a rooted device, you can inspect the shared preferences file created in the app sandbox. For example, run the following command:

```sh
adb shell cat /data/data/org.owasp.mastestapp/shared_prefs/MasSharedPref_Sensitive_Data.xml
adb shell su -c 'cat /data/data/org.owasp.mastestapp/shared_prefs/MasSharedPref_Sensitive_Data.xml'
```

Which returns:

{{ MasSharedPref_Sensitive_Data.xml }}

All unencrypted entries can be leveraged by an attacker.
The unencrypted token and private-key values are visible in the XML file if the app data directory can be accessed.

## Steps

Expand Down
48 changes: 17 additions & 31 deletions knowledge/android/MASVS-STORAGE/MASTG-KNOW-0036.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,19 @@ platform: android
title: Shared Preferences
---

The [`SharedPreferences`](https://developer.android.com/training/data-storage/shared-preferences "Shared Preferences") API is commonly used to permanently save small collections of key-value pairs.
!!! warning

Since Android 4.2 (API level 17) the `SharedPreferences` object can only be declared to be private (and not world-readable, i.e. accessible to all apps). However, since data stored in a `SharedPreferences` object is written to a plain-text XML file so its misuse can often lead to exposure of sensitive data.
Android recommends [`DataStore`](https://developer.android.com/topic/libraries/architecture/datastore) as a modern replacement for `SharedPreferences`. See @MASTG-BEST-0050 for more information.

The [`SharedPreferences`](https://developer.android.com/training/data-storage/shared-preferences "Shared Preferences") API is commonly used to persist small collections of key-value pairs in the app's sandbox storage.

Since Android 4.2 (API level 17), the `MODE_WORLD_READABLE` and `MODE_WORLD_WRITEABLE` flags for `SharedPreferences` have been deprecated because they allow other apps to access the created file. Starting with Android 7.0 (API level 24), using either flag throws a [`SecurityException`](https://developer.android.com/reference/java/lang/SecurityException).

Use `SharedPreferences` in private mode by calling `getSharedPreferences` with `Context.MODE_PRIVATE`. See ["Use SharedPreferences in private mode"](https://developer.android.com/privacy-and-security/security-best-practices#sharedpreferences).

When private mode is used, the XML file containing the key-value data is stored with permissions that restrict access to the app's own Linux user ID. Under the normal Android app sandbox, other apps cannot read this file directly.

However, private mode does not encrypt the data. The values are still written in plaintext in the XML file.

Consider the following example:

Expand All @@ -18,9 +28,7 @@ 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`.
Once the activity has been called, the file `key.xml` will be created, meaning that the username and password are stored in cleartext in `/data/data/<package-name>/shared_prefs/key.xml`:

```xml
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
Expand All @@ -30,32 +38,10 @@ Once the activity has been called, the file key.xml will be created with the pro
</map>
```

`MODE_PRIVATE` makes the file only accessible by the calling app. See ["Use SharedPreferences in private mode"](https://developer.android.com/privacy-and-security/security-best-practices#sharedpreferences).

> Other insecure modes exist, such as `MODE_WORLD_READABLE` and `MODE_WORLD_WRITEABLE`, but they have been deprecated since Android 4.2 (API level 17) and [removed in Android 7.0 (API Level 24)](https://developer.android.com/reference/android/os/Build.VERSION_CODES#N). Therefore, only apps running on an older OS version (`android:minSdkVersion` less than 17) will be affected. Otherwise, Android will throw a [SecurityException](https://developer.android.com/reference/java/lang/SecurityException). If an app needs to share private files with other apps, it is best to use a [FileProvider](https://developer.android.com/reference/androidx/core/content/FileProvider) with the [FLAG_GRANT_READ_URI_PERMISSION](https://developer.android.com/reference/android/content/Intent#FLAG_GRANT_READ_URI_PERMISSION). See [Sharing Files](https://developer.android.com/training/secure-file-sharing) for more details.
[`EncryptedSharedPreferences`](https://developer.android.com/reference/androidx/security/crypto/EncryptedSharedPreferences) is a `SharedPreferences` wrapper from the Jetpack Security Crypto library. It encrypts preference keys with `AES256_SIV`, a deterministic Authenticated Encryption with Associated Data (AEAD) scheme, and preference values with `AES256_GCM`, an AEAD scheme, before writing them to disk. See the [`EncryptedSharedPreferences` source code](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:security/security-crypto/src/main/java/androidx/security/crypto/EncryptedSharedPreferences.java) for implementation details.

You might also use [`EncryptedSharedPreferences`](https://developer.android.com/reference/androidx/security/crypto/EncryptedSharedPreferences), which is wrapper of `SharedPreferences` that automatically encrypts all data stored to the shared preferences.
!!! warning

!!! Warning
The **Jetpack Security Crypto library**, including the `EncryptedFile` and `EncryptedSharedPreferences` classes, has been [deprecated](https://developer.android.com/privacy-and-security/cryptography#jetpack_security_crypto_library). All APIs in the library were deprecated in stable version `1.1.0`, and Android states that there will be no subsequent releases. For existing apps that must continue using `SharedPreferences` for sensitive data, `EncryptedSharedPreferences` may still be a practical mitigation, but it should not be treated as a long term storage strategy. Monitor Android's cryptography and DataStore guidance, and plan a migration to a supported encryption approach when available.

The **Jetpack security crypto library**, including the `EncryptedFile` and `EncryptedSharedPreferences` classes, has been [deprecated](https://developer.android.com/privacy-and-security/cryptography#jetpack_security_crypto_library). However, since an official replacement has not yet been released, we recommend using these classes until one is available.

```kotlin
var masterKey: MasterKey? = null
masterKey = Builder(this)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()

val sharedPreferences: SharedPreferences = EncryptedSharedPreferences.create(
this,
"secret_shared_prefs",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

val editor = sharedPreferences.edit()
editor.putString("username", "administrator")
editor.putString("password", "supersecret")
editor.commit()
```
When using `EncryptedSharedPreferences`, exclude the encrypted preference file from Auto Backup. Android's API reference warns that restoring the file may fail because the key used to encrypt it might no longer be available.
1 change: 1 addition & 0 deletions tests-beta/android/MASVS-STORAGE/MASTG-TEST-0207.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ prerequisites:
- identify-sensitive-data
weakness: MASWE-0006
profiles: [L2]
best-practices: [MASTG-BEST-0050]
knowledge: [MASTG-KNOW-0041]
---

Expand Down
47 changes: 42 additions & 5 deletions tests-beta/android/MASVS-STORAGE/MASTG-TEST-0287.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,49 @@
---
title: References to Sensitive Data Stored Unencrypted via the SharedPreferences API to the App Sandbox
title: Runtime Storage of Unencrypted Data via the SharedPreferences API
platform: android
id: MASTG-TEST-0287
type: [static, code]
type: [dynamic, hooks, manual]
weakness: MASWE-0006
best-practices: []
best-practices: [MASTG-BEST-0050]
profiles: [L1, L2]
prerequisites:
- identify-sensitive-data
knowledge: [MASTG-KNOW-0036]
status: placeholder
note: This test checks if the app is using the SharedPreferences API to store sensitive data (e.g. user credentials, tokens) in an unencrypted format within the app's sandbox. This includes checking for the use of `SharedPreferences` without encryption as well as not using `EncryptedSharedPreferences` or similar secure storage mechanisms.
---

## Overview

In Android, applications can use the [`SharedPreferences`](https://developer.android.com/reference/android/content/SharedPreferences) API to store sensitive data without encryption, typically under the app's private data directory, such as `/data/user/0/<package-name>/shared_prefs/` or `/data/data/<package-name>/shared_prefs/`.

While `MODE_PRIVATE` restricts file access to the app itself, it doesn't protect the data from being read by attackers who gain access to the device's file system (for example, through device compromise, backup extraction, or physical access to rooted/unlocked devices).

This test uses runtime instrumentation to detect when the app writes data via `SharedPreferences` and determines whether sensitive data is being stored unencrypted.
Comment thread
cpholguera marked this conversation as resolved.

Relevant API calls regarding `SharedPreferences` include `SharedPreferences.Editor.putString(...)` and `putStringSet(...)`, which write string values to the XML files in the app's sandbox. There's also `put*` methods for other data types, but strings are the most common way to store sensitive data such as API keys, tokens, passwords, or private keys.

For encryption, relevant API calls include `javax.crypto.Cipher`, `java.security.KeyStore`, or `javax.crypto.KeyGenerator`.

For more information about the `SharedPreferences` API, refer to @MASTG-KNOW-0036.

## Steps

1. Use @MASTG-TECH-0005 to install the app.
2. Use @MASTG-TECH-0043 to hook the relevant API calls.
3. Exercise the app extensively to trigger as many flows as possible and enter sensitive data wherever you can.
4. Use @MASTG-TECH-0008 to retrieve the app's `SharedPreferences` XML files.

## Observation

The output should contain a list of all calls to `SharedPreferences` write methods, including the keys, values, and stack traces showing where in the app's code these calls originate. The trace should also include related cryptographic operations that may indicate encryption is being used.

The output should also contain the contents of all `SharedPreferences` XML files.

## Evaluation

The test case fails if sensitive data is written to `SharedPreferences` without being encrypted first.

**Further Validation Required:**

1. **High-level trace inspection**: Review the sequence of calls from the hook output to identify if `SharedPreferences.Editor.putString` or `putStringSet` calls are preceded by `Cipher` operations. Values written without prior encryption are likely stored in cleartext.
2. **Pattern matching**: Use a secrets detection tool (for example, @MASTG-TOOL-0144) to scan the output for known secret patterns such as API keys, tokens, passwords, or private keys.
Comment thread
cpholguera marked this conversation as resolved.
3. **Manual verification**: Use the stack traces from the hook output to navigate to the relevant code locations in the reversed app (@MASTG-TECH-0023) and trace back the source of the values being written to confirm whether they contain sensitive data and whether encryption is applied.
Loading