Appearance
本文译自Use cryptography in mobile apps the right way
加密是保护数据的重要手段,但是不少开发者经常误用加密措施.
为什么需要加密
虽然安卓和ios都提供了沙盒机制来隔离不同App之间的运行环境,但是对于敏感数据,还是必须进行保护. 至少应该进行监管要求的最低线保护. 另外,因为App中可能存在的各种泄露App内部文件的安全漏洞:
- 通过WebView泄露
- 通过contentProviders泄露
- 通过隐式的intent(implicit intents)
- 其他方式
加密可以有效保证,即使存在这些问题,攻击者也因为加密手段的存在而很难获取到什么好处. 可以读取内部文件的漏洞,只会导致相关文件内容泄露,而不会导致整个秘钥以及其他文件泄露. 而写文件则会导致用户账户的自动注销.
加密需要遵循的三条军规
1. 不要硬编码秘钥
硬编码秘钥意味着可以从源码中直接提取秘钥,而这其实和没有加密是没有区别的. 安卓中的错误示例: ios中的错误示例:
2. 可预测的加密秘钥
秘钥虽然使用了随机数来生成,但是随机数的种子却是可预测的,这同样会导致秘钥很容易推测出来.
常见的错误就是使用固定的种子:
java
SecureRandom secureRandom = new SecureRandom("known_seed".getBytes());
KeyGenerator generator = KeyGenerator.getInstance("AES");
generator.init(256, secureRandom);
Key key = generator.generateKey();
或者使用伪随机数:
java
private byte[] generateKey() {
byte[] key = new byte[128];
Random random = new Random();
for (int i = 0; i < 128; i++) {
key[i] = (byte) random.nextInt(256);
}
return key;
}
private byte[] encrypt(byte[] data) {
SecretKeySpec skeySpec = new SecretKeySpec(generateKey(), "AES");
//...
}
或者秘钥使用未初始化的默认值,不同于c++语言,java中数组未初始化,默认值是0:
java
private byte[] encrypt(byte[] data) {
byte[] key = new byte[128];
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
//...
}
3. 使用系统提供加密方法
安卓请用keystore
安卓提供了KeyStore, App只能通过API来获取秘钥,不能直接读取相关文件. 相关秘钥存储在/data/misc/keystore
. 普通用户无法直接读取. 当然如果手机root了,是可以读取的, 这也证明了对手机root的危害.
ios请用安全隔离区(Secure Enclave
)
Secure Enclave是苹果提供的存储秘钥以及生物信息的手段,它是集成到SoC的专用安全子系统,独立于处理器. 即使处理器遭到入侵,也可以保护敏感数据的安全. 关于安全隔离区的介绍,可以参考苹果官网.
其他
当然就算你使用了遵循了上述规则,也不能保证你的数据100%安全. 如果你的App存在ACE(arbitrary code execution)问题,那么什么保护手段都将是无效的. 不过幸好,ACE是一种非常严重的安全漏洞,出现的概率相对是非常低的.