3. Android安全模型
Android 的安全模型不是单一机制,而是由多个层次叠加而成的纵深防御体系。应用沙箱负责隔离进程与数据,权限机制控制应用能访问哪些受保护资源,应用签名保证应用来源与升级链的可信性,SELinux 在内核层强制约束进程行为,硬件安全模块(如 TEE、StrongBox)则为密钥与认证提供物理级信任根。理解它们之间的关系,是后续使用 Android Keystore 与密钥服务的基础。
一、核心原理:五层安全机制如何协同
从下往上看,Android 安全模型大致分为五层:
- 硬件信任根层:包括 TEE(可信执行环境)、StrongBox、硬件密钥库。它们提供密钥不可导出、防物理提取、防回滚等能力。
- 内核强制访问控制层:SELinux 以标签和策略约束进程对文件、socket、设备节点的访问,即使 root 进程也受策略限制。
- 应用隔离层:每个应用运行在独立 UID 的沙箱中,拥有私有数据目录,默认无法读取其他应用数据。
- 权限与签名层:权限决定应用能调用哪些受保护 API;签名决定应用能否被安装、升级以及能否申请 signature 级权限。
- 应用框架层:Keystore、KeyChain、BiometricPrompt 等 API 将上述能力封装为开发者可调用的接口。
这五层不是并列关系,而是逐层依赖:Keystore 中的密钥最终可能由 TEE 或 StrongBox 保护;SELinux 限制 keystore 守护进程只能访问特定设备节点;应用沙箱决定谁能调用 Keystore;签名则决定应用是否被允许使用某些密钥别名或权限。
二、方法流程:一次 Keystore 密钥生成请求经历了什么
以应用调用 KeyGenerator.getInstance("AES", "AndroidKeyStore") 生成密钥为例,请求会依次穿过上述五层:
- 应用进程在自身沙箱内发起调用,Binder 将请求发送给 keystore2 守护进程。
- SELinux 检查应用域是否有权限向 keystore 域发送 Binder 消息,同时检查 keystore 域能否访问底层密钥设备节点。
- keystore2 校验调用者 UID 与签名信息,确认该应用是否有权创建指定别名的密钥。
- 若密钥需要硬件保护,keystore2 通过 TEE 或 StrongBox 驱动将密钥生成请求下发到安全世界。
- 密钥在 TEE/StrongBox 内生成,私钥或对称密钥永不离开安全环境,仅返回密钥句柄。
- 应用后续加解密时,只传递句柄与数据,由安全环境完成运算并返回结果。
关键结论:Keystore 不是简单的文件存储,而是安全模型各层能力的汇聚点。没有沙箱,任何应用都能调用;没有权限与签名,无法限制调用者;没有 SELinux,守护进程可能被越权访问;没有硬件信任根,密钥仍可能被软件提取。
三、案例/场景:签名不一致导致 Keystore 密钥失效
某团队在调试环境使用 debug 签名生成了一批 Keystore 密钥,上线时切换为 release 签名。结果发现:
- 应用可以正常安装,但读取原有密钥别名时抛出
KeyStoreException: Key not found。 - 部分依赖 signature 级权限的接口返回
SecurityException。 - BiometricPrompt 绑定的密钥无法再用于认证。
原因在于:Android Keystore 将密钥与调用者的 UID 和签名证书绑定。签名变更后,系统认为这是“另一个应用”,原有密钥不可访问。这体现了签名层与 Keystore 的强耦合关系。
# 查看应用签名摘要
apksigner verify --print-certs app-release.apk
# 典型输出
Signer #1 certificate DN: CN=Example, O=Demo
Signer #1 certificate SHA-256 digest: 3a:7f:...
注意:不要在不同签名之间复用 Keystore 别名。若必须迁移,应在旧签名版本中导出可迁移数据,或设计密钥轮换与重新绑定流程。
四、误区与复盘:常见理解偏差
| 误区 | 正确理解 |
|---|---|
| “应用沙箱就是权限机制” | 沙箱解决隔离,权限解决授权,两者互补但不同层。 |
| “有 SELinux 就不需要签名” | SELinux 约束进程行为,签名约束应用身份与升级链,缺一不可。 |
| “Keystore 密钥一定在 TEE 中” | 取决于密钥生成参数与设备能力,部分密钥仍由软件保护。 |
| “root 后 Keystore 就完全失效” | SELinux 与硬件信任根仍能提供一定保护,但 root 会显著降低整体安全性。 |
| “签名只影响安装” | 签名还影响权限授予、密钥绑定、数据共享与升级兼容性。 |
复盘时可以用一条判断链快速定位问题:先确认应用签名与 UID 是否变化,再检查权限是否授予,然后查看 SELinux 审计日志中是否有 avc: denied,最后确认密钥是否要求硬件支持以及设备是否具备 TEE/StrongBox。沿着这条链排查,大多数 Keystore 与密钥服务问题都能快速收敛。
实践建议:在开发阶段就固定签名配置,使用 android:sharedUserId 需谨慎;对高价值密钥显式设置 setIsStrongBoxBacked(true) 或 setUserAuthenticationRequired(true),并始终通过 KeyAttestation 验证密钥的真实保护级别。