21、安全机制:SELinux、沙箱、Keystore、Verified Boot与TEE
Android 的安全体系,说实话,是我这些年研究下来觉得最「拧巴」也最精妙的部分。拧巴在哪呢?它既要给开发者足够的自由度,又要把用户数据锁得死死的。精妙之处在于,它用一套层层嵌套的机制,把「信任」这件事从硬件一路传递到应用层。
今天咱们就把这五个核心组件掰开揉碎聊一聊。SELinux、沙箱、Keystore、Verified Boot、TEE。嗯,每个都是硬骨头,但啃下来之后,你对 Android 底层的理解会上一个台阶。
5.1 SELinux:强制访问控制的「铁闸」
先说说 SELinux。我记得刚接触 Android 时,总被它的权限拒绝日志搞懵。明明 root 了,为什么还是不能读写某个文件?后来才明白,Linux 传统的 DAC(自主访问控制)在 SELinux 面前就是个摆设。
SELinux 用的是 MAC(强制访问控制)。说白了,就是系统定了一套铁规矩,谁都不能改。哪怕你是 root,也得按规矩来。
它的核心概念就两个:主体(进程)和客体(文件、socket 等)。每个主体和客体都有一个安全上下文,比如:
u:r:untrusted_app:s0:c15,c256,c512,c768
这串东西看着复杂,其实拆开就明白了:
- u:用户,Android 里基本都是 u
- r:角色,一般也是 r
- untrusted_app:类型(Type),这是最关键的
- s0:安全级别,MLS 用的
- c15,c256,...:类别,用于隔离不同应用
规则怎么写呢?看个例子:
allow untrusted_app app_data_file:file rw_file_perms;
这条规则的意思是:允许 untrusted_app 类型的进程,对 app_data_file 类型的文件,执行读写操作。少一条规则,权限就过不去。
5.2 沙箱:应用之间的「隔离墙」
沙箱这个概念,说白了就是「你的应用住你的房间,我的应用住我的房间,谁也别串门」。Android 从设计之初就把这个机制刻在骨子里了。
每个应用安装时,系统会分配一个独立的 UID(用户 ID)。这个 UID 决定了:
- 应用的数据目录(/data/data/包名)只有它自己能读写
- 应用的进程只能访问自己的资源
- 默认情况下,应用之间不能互相通信(除非用 Binder 显式授权)
你想想看,如果没有沙箱,一个恶意应用就能随便读取你的微信聊天记录,那还得了?
不过沙箱也不是万能的。我记得有个项目,需要两个应用共享数据,当时我用了 SharedUserId。嗯,这玩意儿现在已经被 Google 标记为废弃了,建议用 ContentProvider 或者文件共享。
5.3 Keystore:密钥的「保险柜」
Keystore 是什么?说白了,就是一个专门存密钥的地方。但它不是普通的文件存储,而是有硬件加持的。
Android 的 Keystore 系统分两层:
- 软件层:KeyStore 服务,管理密钥的生命周期
- 硬件层:TEE(后面会讲)或者 Secure Element,真正执行加密操作
为什么需要硬件?因为密钥一旦被软件拿到,就容易被 dump 出来。而在 TEE 里,密钥永远不离开安全环境。应用只能告诉 TEE:「帮我用密钥A签名这段数据」,然后拿到签名结果,但永远看不到密钥本身。
看个生成密钥的例子:
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
"my_key",
KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
.setDigests(KeyProperties.DIGEST_SHA256)
.setUserAuthenticationRequired(true)
.build();
KeyGenerator kg = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
kg.init(spec);
kg.generateKey();
注意那个 setUserAuthenticationRequired(true),意思是使用这个密钥前,必须验证用户身份(指纹或锁屏密码)。嗯,这就是为什么你的支付应用每次都要你刷脸。
5.4 Verified Boot:启动链的「信任锚」
Verified Boot,中文叫「验证启动」。它的逻辑很简单:从硬件开始,一级一级验证,确保每一层都没被篡改。
流程大概是这样的:
- SoC 里的 BootROM 先验证 Bootloader 的签名
- Bootloader 验证 Boot 分区的签名(包含 kernel 和 ramdisk)
- Kernel 验证 System 分区的完整性
- System 服务验证 APK 的签名
每一层都信任上一层的公钥。这个信任链的根,就是硬件里烧录的密钥。谁要是改了系统文件,启动时就会报错,直接进不了系统。
我画了一张图,帮你理解这个链条:
这里有个坑:如果你刷了第三方 ROM 或者 Magisk,Verified Boot 就会失败。所以现在很多手机解锁 bootloader 后,会清空所有数据。为什么?因为解锁意味着信任链断了,系统无法保证数据安全,干脆全清了。
5.5 TEE:可信执行环境
TEE,全称 Trusted Execution Environment。它和普通操作系统(REE,Rich Execution Environment)是隔离的。说白了,就是手机里有两个世界:
- REE:你平时用的 Android 系统,功能丰富但不够安全
- TEE:一个精简的安全系统,只做加密、签名等敏感操作
这两个世界怎么通信?通过 SMC(Secure Monitor Call)指令。REE 发起请求,CPU 切换到安全模式,TEE 处理完再切回来。
TEE 里跑的是什么?通常是 Trusted Applications(TA),比如:
- 指纹比对(你的指纹模板就存在 TEE 里)
- 支付密钥管理
- DRM 解密(看高清视频时)
我举个例子你就明白了。你用微信支付时,流程是这样的:
- 微信 App 在 REE 里发起支付请求
- 系统把请求发给 TEE 里的支付 TA
- TA 用存储在 TEE 里的密钥签名交易数据
- 签名结果返回给微信 App
- 微信把签名发给服务器验证
整个过程,密钥从未离开 TEE。就算 Android 系统被攻破了,攻击者也拿不到密钥。
5.6 五者如何协同工作?
这五个组件不是孤立的,它们环环相扣:
| 组件 | 作用 | 依赖 |
|---|---|---|
| Verified Boot | 保证系统启动时未被篡改 | 硬件信任根(BootROM) |
| SELinux | 限制进程权限,防止越权 | 内核支持,策略文件 |
| 沙箱 | 隔离应用数据 | Linux UID 机制 |
| Keystore | 安全存储密钥 | TEE 或 Secure Element |
| TEE | 提供安全执行环境 | 硬件支持(ARM TrustZone) |
举个例子,你打开一个银行 App:
- Verified Boot 保证系统没被篡改
- 沙箱保证银行 App 的数据不被其他应用读取
- SELinux 保证银行 App 的进程不能乱访问系统文件
- 登录时,Keystore 在 TEE 里生成密钥对,公钥发给服务器
- 每次交易,TEE 用私钥签名,确保交易不可抵赖
你看,每一层都在保护上一层的安全。这就是 Android 安全体系的精髓——纵深防御。
公众号:蓝海资料掘金营,微信deep3321