别再把Token明文存进SharedPreferences了
很多App登录完,随手就把Token塞进SharedPreferences或者UserDefaults里,以为万事大吉。可一旦手机被root或越狱,这些数据就像贴在墙上的便签,谁都能看。
想象一下:你在咖啡馆连公共Wi-Fi,黑客用工具一扫,把你银行App的Token读出来,直接冒充你操作账户——这可不是危言耸听,而是真实可能发生的事。
Android:用EncryptedSharedPreferences更靠谱
Google在Security库中提供了EncryptedSharedPreferences,它基于主密钥对存储内容自动加密。只要设备支持KeyStore,加密密钥就不会被轻易导出。
String masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC);
SharedPreferences encryptedSharedPrefs = EncryptedSharedPreferences.create(
"secret_prefs",
masterKeyAlias,
context,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
);
encryptedSharedPrefs.edit().putString("auth_token", token).apply();这样存进去的Token,即使被人导出文件,看到的也是一串乱码。
iOS:钥匙串(Keychain)才是正道
UserDefaults和NSUserDefaults跟Android的SharedPreferences一样不安全。iOS有专门的安全存储机制——Keychain。它由系统级加密保护,App卸载后数据还能选择保留,适合存Token这类敏感信息。
let query = [
kSecClass as String: kSecClassGenericPassword as String,
kSecAttrService as String: "com.yourapp.auth",
kSecAttrAccount as String: "token",
kSecValueData as String: token.data(using: .utf8)!
]
SecItemAdd(query as CFDictionary, nil)Keychain中的数据受设备密码和Secure Enclave保护,就算备份到iCloud,默认也不会同步敏感项。
跨平台方案:React Native和Flutter怎么办?
如果你用的是Flutter,推荐flutter_secure_storage。它在Android底层用EncryptedSharedPreferences,在iOS走Keychain,自动适配。
final storage = FlutterSecureStorage();
await storage.write(key: "token", value: "your-jwt-token");
String? token = await storage.read(key: "token");React Native可以选react-native-sensitive-info,配置好之后,存取Token就跟调API一样简单。
别忘了Token本身也要“瘦身”
有些开发者图省事,把用户所有权限、角色、信息全塞进JWT Token里,结果Token又大又容易泄露。建议Token只保留必要标识,比如用户ID和过期时间,其他信息通过服务端接口按需获取。
另外,配合refresh token机制,让access token生命周期短一点。哪怕被截获,有效期也很短,降低风险。
防抓包:HTTPS + 证书绑定
就算Token存得再安全,传输过程中被中间人劫持也白搭。除了用HTTPS,还可以做SSL Pinning(证书绑定),确保App只跟自家服务器通信。
像OkHttp(Android)和AFNetworking(iOS)都支持证书校验。虽然会增加更新证书的运维成本,但对金融、医疗类App来说,这笔投入值得。
安全不是一次性任务,而是一层层叠加的防护网。从存储、传输到使用,每个环节都不能掉链子。把Token当成银行卡密码来保护,你的App才真正值得用户信任。