1. 从“保险箱”到“金库”:Android Keystore到底是什么?
如果你开发过需要处理密码、支付或者身份认证的Android应用,那你肯定对“如何安全地存储密钥”这个问题头疼过。把密钥直接写在代码里?那等于把家门钥匙藏在脚垫下面。存在SharedPreferences里?稍微有点经验的攻击者都能轻松拿到。几年前,我也在这个问题上栽过跟头,直到我开始认真研究Android Keystore,才发现它才是解决这个问题的“正解”。
你可以把Android Keystore想象成一个由系统专门为你打造的、高度安全的“数字保险箱”。这个保险箱最核心的特点是:它把你的密钥材料(比如RSA的私钥、AES的密钥)隔离在你的应用进程之外。这意味着,即使你的应用被恶意代码侵入,或者因为内存泄露导致数据被读取,攻击者也很难直接从这个保险箱里把原始密钥“偷”出来。它提供了一套API,让你可以生成密钥、导入密钥,然后用这些密钥去执行签名、验签、加密、解密这些操作,但你永远接触不到密钥的“真身”。这从根本上杜绝了应用层无意中泄露密钥的风险。
但这个“保险箱”的坚固程度,其实是有区别的。在早期(Android 6.0之前),这个保险箱可能只是软件层面的一道锁,虽然比放在外面强,但如果系统内核被攻破,锁还是有被撬开的可能。真正的飞跃来自于硬件支持。从Android 6.0开始,借助手机SoC芯片里的一个特殊区域——可信执行环境(TEE),这个保险箱升级成了“硬件金库”。TEE可以理解为CPU里的一个独立、安全的小王国,它与我们日常运行Android系统的主操作系统(Rich OS)在硬件层面就隔离开了。你的密钥可以直接在这个“金库”里生成、存储和使用,整个生命周期都不离开这个安全区域。即使Android系统本身被恶意软件完全控制,它也无力从TEE里把密钥抢走。这种基于硬件的保护,才是高安全场景的底气所在。
我刚开始接触时,觉得这些概念离日常开发很远。但后来做一个金融类的应用,涉及到本地敏感数据的加密存储时,就不得不面对这个问题。不用Keystore,安全审计根本过不了;用了它,才发现原来系统已经为我们准备了这么强大的工具。理解Keystore,不仅是学习几个API调用,更是建立一种“密钥不应该被应用直接持有”的安全思维,这是开发安全应用的第一步。
2. 不只是存储:Keystore的密钥“紧箍咒”
很多人以为Keystore就是个安全的存储柜,放进去就完事了。其实不然,它更强大的地方在于能给密钥戴上“紧箍咒”,严格规定它“能干什么、什么时候能干”。这叫做密钥授权(Key Authorization)。你在创建或导入一个密钥时,可以给它设定一系列的使用限制,这些限制会通过密码学方式与密钥本身绑定,并且由Keystore(在硬件支持下由TEE)强制执行,终生不可更改。
举个例子,最常用的一个“紧箍咒”就是用户身份验证绑定。比如你开发一个笔记应用,可以用一个密钥来加密用户的私密笔记。你可以这样设定:这个密钥必须在使用者通过锁屏密码(或指纹)验证后的30秒内才能使用。代码里大概是这样体现的(以KeyGenParameterSpec为例):
KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(
alias,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setUserAuthenticationRequired(true) // 关键:要求用户认证
.setUserAuthenticationValidityDurationSeconds(30); // 认证后有效期30秒
// 如果是指纹绑定,还可以设置.setUserAuthenticationParameters
这样一来,即使用户的手机丢了,捡到的人在不解锁手机(或30秒超时后)的情况下,应用也无法用这个密钥解密出任何内容。这比单纯依赖应用自己的登录密码要安全得多,因为验证环节下沉到了系统级的、可能由硬件保护的锁屏机制。
另一个重要的“紧箍咒”是密钥用途限制。你可以精确指定一个密钥是只能用来签名,
350



被折叠的 条评论
为什么被折叠?



