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 类型的文件,执行读写操作。少一条规则,权限就过不去。

避坑指南:我曾经在调试一个系统服务时,发现它老是无法访问某个 socket。查了半天,原来是 SELinux 策略里少写了一个 allow 规则。记住,加新功能时,先看看 avc 日志,那里会告诉你缺什么权限。

5.2 沙箱:应用之间的「隔离墙」

沙箱这个概念,说白了就是「你的应用住你的房间,我的应用住我的房间,谁也别串门」。Android 从设计之初就把这个机制刻在骨子里了。

每个应用安装时,系统会分配一个独立的 UID(用户 ID)。这个 UID 决定了:

  • 应用的数据目录(/data/data/包名)只有它自己能读写
  • 应用的进程只能访问自己的资源
  • 默认情况下,应用之间不能互相通信(除非用 Binder 显式授权)

你想想看,如果没有沙箱,一个恶意应用就能随便读取你的微信聊天记录,那还得了?

不过沙箱也不是万能的。我记得有个项目,需要两个应用共享数据,当时我用了 SharedUserId。嗯,这玩意儿现在已经被 Google 标记为废弃了,建议用 ContentProvider 或者文件共享。

核心要点:沙箱 + UID 机制,是 Android 安全的第一道防线。它保证了即使应用被攻破,攻击者也拿不到其他应用的数据。

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),意思是使用这个密钥前,必须验证用户身份(指纹或锁屏密码)。嗯,这就是为什么你的支付应用每次都要你刷脸。

注意:Keystore 的密钥一旦生成,就不能导出。如果你需要备份密钥,得用 KeyChain 或者自己实现密钥托管。我见过有人试图直接读 Keystore 文件,结果发现全是加密后的乱码。

5.4 Verified Boot:启动链的「信任锚」

Verified Boot,中文叫「验证启动」。它的逻辑很简单:从硬件开始,一级一级验证,确保每一层都没被篡改。

流程大概是这样的:

  1. SoC 里的 BootROM 先验证 Bootloader 的签名
  2. Bootloader 验证 Boot 分区的签名(包含 kernel 和 ramdisk)
  3. Kernel 验证 System 分区的完整性
  4. System 服务验证 APK 的签名

每一层都信任上一层的公钥。这个信任链的根,就是硬件里烧录的密钥。谁要是改了系统文件,启动时就会报错,直接进不了系统。

我画了一张图,帮你理解这个链条:

BootROM 硬件信任根 Bootloader 验证Boot分区 Kernel 验证System分区 System服务 验证APK签名 验证 验证 验证 信任链传递 每一层都验证下一层的签名,确保从硬件到应用都未被篡改 任何一层验证失败,系统都会拒绝启动或进入恢复模式 🔒 Verified Boot 保证系统完整性

这里有个坑:如果你刷了第三方 ROM 或者 Magisk,Verified Boot 就会失败。所以现在很多手机解锁 bootloader 后,会清空所有数据。为什么?因为解锁意味着信任链断了,系统无法保证数据安全,干脆全清了。

个人经验:我调试过一台设备,每次开机都卡在 Google 标志。查了 log 发现是 dm-verity 报错。原来是 system 分区被不小心写入了数据。用 fastboot 重新刷入原厂镜像才解决。嗯,从那以后我刷机前都会先备份。

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 解密(看高清视频时)

我举个例子你就明白了。你用微信支付时,流程是这样的:

  1. 微信 App 在 REE 里发起支付请求
  2. 系统把请求发给 TEE 里的支付 TA
  3. TA 用存储在 TEE 里的密钥签名交易数据
  4. 签名结果返回给微信 App
  5. 微信把签名发给服务器验证

整个过程,密钥从未离开 TEE。就算 Android 系统被攻破了,攻击者也拿不到密钥。

核心价值:TEE 把敏感操作和普通操作系统隔离开,实现了「即使系统被攻破,密钥依然安全」的效果。这是 Android 安全体系的最后一道防线。

5.6 五者如何协同工作?

这五个组件不是孤立的,它们环环相扣:

组件 作用 依赖
Verified Boot 保证系统启动时未被篡改 硬件信任根(BootROM)
SELinux 限制进程权限,防止越权 内核支持,策略文件
沙箱 隔离应用数据 Linux UID 机制
Keystore 安全存储密钥 TEE 或 Secure Element
TEE 提供安全执行环境 硬件支持(ARM TrustZone)

举个例子,你打开一个银行 App:

  1. Verified Boot 保证系统没被篡改
  2. 沙箱保证银行 App 的数据不被其他应用读取
  3. SELinux 保证银行 App 的进程不能乱访问系统文件
  4. 登录时,Keystore 在 TEE 里生成密钥对,公钥发给服务器
  5. 每次交易,TEE 用私钥签名,确保交易不可抵赖

你看,每一层都在保护上一层的安全。这就是 Android 安全体系的精髓——纵深防御。

最后提醒一句:别以为有了这些机制就万无一失。我见过有人通过侧信道攻击(比如分析功耗波动)从 TEE 里窃取密钥。安全是个持续对抗的过程,没有绝对的安全。

公众号:蓝海资料掘金营,微信deep3321