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;签名则决定应用是否被允许使用某些密钥别名或权限。

Android 安全模型分层与 Keystore 调用链 应用框架层 Keystore API KeyChain BiometricPrompt KeyAttestation 权限与签名层 运行时权限 签名校验 signature 级权限 应用升级链 应用沙箱层 独立 UID 私有数据目录 进程隔离 Binder IPC 边界 SELinux 强制访问控制层 域(Domain) 类型(Type) 策略规则 neverallow 约束 硬件信任根层 TEE 可信执行环境 StrongBox 硬件密钥库 防物理提取

二、方法流程:一次 Keystore 密钥生成请求经历了什么

以应用调用 KeyGenerator.getInstance("AES", "AndroidKeyStore") 生成密钥为例,请求会依次穿过上述五层:

  1. 应用进程在自身沙箱内发起调用,Binder 将请求发送给 keystore2 守护进程。
  2. SELinux 检查应用域是否有权限向 keystore 域发送 Binder 消息,同时检查 keystore 域能否访问底层密钥设备节点。
  3. keystore2 校验调用者 UID 与签名信息,确认该应用是否有权创建指定别名的密钥。
  4. 若密钥需要硬件保护,keystore2 通过 TEE 或 StrongBox 驱动将密钥生成请求下发到安全世界。
  5. 密钥在 TEE/StrongBox 内生成,私钥或对称密钥永不离开安全环境,仅返回密钥句柄。
  6. 应用后续加解密时,只传递句柄与数据,由安全环境完成运算并返回结果。

关键结论: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 验证密钥的真实保护级别。