2. 固件安全基础
固件是运行在硬件与操作系统之间的底层软件,通常固化在 SPI Flash、eMMC、UFS 或 ROM 中,负责上电初始化、硬件自检、外设配置,并最终把控制权交给引导加载程序或操作系统。与普通应用软件不同,固件一旦被篡改,攻击者可以在操作系统安全机制生效之前获得执行机会,因此固件安全是整个可信计算链条的起点。理解固件防降级与回滚保护,必须先看清固件的组成、启动流程、信任根、安全启动与度量启动之间的关系,以及攻击者最常利用的入口。
一、固件概念与组成
典型设备的固件并非单一镜像,而是由多个阶段和多个存储区域组成。以嵌入式 Linux 或 Android 设备为例,常见组成包括:
- Boot ROM:芯片出厂时固化的只读代码,是上电后执行的第一段程序,通常不可修改,承担最初始的信任锚点角色。
- 一级引导程序(SPL/Preloader):初始化时钟、内存控制器、存储控制器,加载下一阶段引导程序。
- 二级引导程序(U-Boot、LK、ABL 等):初始化更多外设,校验并加载内核与设备树。
- 安全固件区:如 TEE OS、安全监控固件、电源管理固件、基带固件等。
- 可变数据区:环境变量、回滚计数器、版本号、密钥槽、日志区等。
这些组件分布在不同的存储介质和分区中,启动时按固定顺序逐级加载。任何一级被替换或降级,都可能破坏后续所有安全假设。
二、启动流程与信任根
设备上电后,CPU 首先从固定地址取指,执行 Boot ROM 中的代码。Boot ROM 会读取启动介质中的第一阶段引导程序,验证其签名或校验值,验证通过后跳转执行。随后每一级引导程序验证下一级镜像,直到内核和系统分区。这个逐级验证的过程称为信任链,而信任链的起点就是信任根(Root of Trust, RoT)。
信任根通常由三部分构成:
- 可信计算基:不可修改的 Boot ROM 代码。
- 可信密钥:烧录在 OTP/eFuse 中的公钥哈希或根公钥。
- 可信度量:由硬件或 ROM 代码计算出的初始摘要值。
信任根必须满足“不可篡改、可验证、可度量”三个条件。如果根公钥可以被替换,或者 Boot ROM 存在可跳过的验证分支,那么整条信任链就形同虚设。
核心原则:信任根不可变,信任链逐级传递,每一级只信任经过验证的下一级。
三、安全启动与度量启动
安全启动(Secure Boot)和度量启动(Measured Boot)经常被混淆,但二者目标不同。安全启动强调“验证通过才执行”,是一种强制门禁;度量启动强调“记录并报告”,是一种可审计的完整性证据。安全启动解决“能不能启动”,度量启动解决“启动了什么、是否可信”。
| 对比项 | 安全启动 | 度量启动 |
|---|---|---|
| 核心动作 | 验签、校验哈希、失败则阻断 | 计算摘要、扩展 PCR、记录日志 |
| 执行时机 | 每一级加载前 | 每一级加载前后均可 |
| 失败后果 | 停止启动或进入恢复模式 | 不直接阻断,但远端可判定异常 |
| 典型技术 | RSA/ECDSA 签名、哈希白名单 | TPM PCR、DICE、事件日志 |
| 防降级作用 | 可结合版本号拒绝旧镜像 | 可发现版本回退痕迹 |
在防降级场景中,安全启动通常需要引入版本号或安全计数器。仅验证签名是不够的,因为攻击者可以重新签名一个旧版本镜像,或者直接回滚到官方旧固件。只有把“版本不低于当前最低允许版本”作为验证条件之一,才能阻止回滚。
四、常见攻击面
固件攻击面贯穿启动全流程,常见入口包括:
- Boot ROM 漏洞:如 USB 下载模式绕过、缓冲区溢出、验证分支跳过。
- 引导程序配置错误:未锁定 fastboot、未关闭调试串口、环境变量可写。
- 签名验证缺陷:只校验部分分区、哈希算法过时、公钥可替换。
- 回滚攻击:刷入旧版有漏洞固件,再利用已知漏洞提权。
- 物理攻击:SPI Flash 离线读写、eMMC 直接访问、故障注入。
- 供应链攻击:生产工具、烧录镜像、OTA 服务器被污染。
常见误区:认为“开了安全启动就安全了”。实际上,安全启动只覆盖启动路径,若 OTA 更新流程、恢复模式或调试接口未纳入同一验证体系,攻击者仍可绕过。
五、场景复盘:一次典型的回滚攻击
某设备安全启动已开启,但版本校验仅比较字符串且允许降级。攻击者获取旧版固件后,通过官方 OTA 通道重新刷入。旧版固件中存在已修复的 fastboot 漏洞,攻击者随后解锁引导程序并刷入自定义内核,最终获取 root 权限。复盘发现三个问题:第一,版本号未与安全计数器绑定;第二,OTA 包未强制要求版本递增;第三,恢复模式未校验版本下限。修复方案是在 Boot ROM 之后的每一级验证中加入防回滚计数器,并将计数器存储在 OTP 或 TEE 保护区域,任何降级尝试直接拒绝启动。
# 典型安全启动验证伪代码
verify_image(image, pubkey, min_version):
digest = hash(image.payload)
if not verify_signature(digest, image.signature, pubkey):
return REJECT
if image.version < min_version:
return REJECT_ROLLBACK
return ACCEPT
从工程实践看,固件安全不是单点技术,而是“信任根 + 逐级验证 + 版本约束 + 度量记录 + 攻击面收敛”的组合。只有把启动流程中的每一级都纳入同一安全策略,防降级与回滚保护才有可靠基础。