如何保障应用中SharedPreferences数据安全?安全审计仍遭破解
Hey there, let's dig into why your SharedPreferences security setup got breached and how you can tighten things up.
1. Default MODE_PRIVATE SharedPreferences
First off, MODE_PRIVATE only prevents other apps on the same device from accessing your SharedPreferences — it does nothing to protect against root access. When a device is rooted, attackers can directly navigate to /data/data/[your-app-package]/shared_prefs/ and read the plaintext XML files stored there. Your code here stores data in plaintext, so it's trivial for a rooted device user to extract:
SharedPreferences sharedPreferences = context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putString("key", value); editor.commit();
2. SecurePreferences Limitations
The third-party SecurePreferences library does encrypt data, but it often falls short due to common implementation mistakes:
- Hardcoded encryption keys: If you embedded the encryption key directly in your code, attackers can easily extract it by decompiling your APK.
- Insecure key storage: Some implementations store the encryption key in the same SharedPreferences file it's supposed to protect, making the encryption useless.
- Outdated encryption practices: Older versions of the library might use weak algorithms (like ECB mode) or insufficient key lengths, which can be cracked with modern tools.
Here are actionable steps to make your SharedPreferences far more resilient:
- Leverage Android Keystore for key management: Android Keystore generates and stores encryption keys in a hardware-backed secure environment (if the device supports it). Keys stored here can't be exported, so attackers can't get their hands on them even if the device is rooted. Example setup:
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); // Generate a new AES key if it doesn't exist if (!keyStore.containsAlias("my_app_secure_key")) { KeyGenerator keyGenerator = KeyGenerator.getInstance( KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"); keyGenerator.init(new KeyGenParameterSpec.Builder( "my_app_secure_key", KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setUserAuthenticationRequired(false) // Set to true if you want biometric lock .build()); keyGenerator.generateKey(); } // Use this key to encrypt your data before saving to SharedPreferences - Encrypt both keys and values: Don't just encrypt the sensitive values — encrypt the keys you use in SharedPreferences too. This way, even if attackers get the encrypted file, they won't know which fields correspond to sensitive data.
- Add biometric authentication for high-risk data: For extremely sensitive data (like auth tokens or payment details), require biometric verification before decrypting. Pair this with
setUserAuthenticationRequired(true)in your Keystore setup, so the key can only be used after the user passes biometric check. - Avoid storing critical data in SharedPreferences: If you're dealing with data like passwords or credit card numbers, skip SharedPreferences entirely. Use encrypted Room databases (with SQLCipher) or store small pieces of data directly in Keystore.
- Enable code obfuscation: Turn on ProGuard/R8 in your build setup. This makes decompiled code much harder to read, especially for your encryption logic.
Remember, no security measure is 100% unbreakable, but combining these steps will drastically increase the effort required for attackers to access your users' data.
内容的提问来源于stack exchange,提问作者Nitin Sharma

