4、安全启动链:信任根(RoT)建立、BootROM安全、U-Boot安全加固

安全启动链,说白了就是给设备装上一道「从娘胎里就带出来的信任机制」。我做了这么多年固件安全,见过太多设备因为启动链被攻破,整个系统就像纸糊的一样。你想想看,如果连最底层的启动代码都不安全,上层做得再花哨也没用。

这一章我们重点聊三个东西:信任根怎么建立、BootROM 有哪些坑、U-Boot 怎么加固。嗯,咱们一个一个来。

4.1 信任根(RoT)的建立

信任根是整个安全启动链的基石。它必须是一个不可篡改的、硬件级别的信任锚点。我个人习惯把 RoT 理解为「第一个说真话的人」——如果第一个人就撒谎,后面全完蛋。

核心原则:信任根必须是硬件绑定的、一次性写入的、不可回滚的。

常见的 RoT 实现方式有几种:

  • 一次性可编程存储器(OTP):比如 eFuse、反熔丝。芯片出厂时烧录公钥哈希或根证书,之后谁也别想改。
  • 硬件安全模块(HSM):独立的安全芯片,比如 TPM、SE。专门干签名验证的脏活累活。
  • CPU 内置 BootROM:掩膜 ROM,出厂就固化,物理上改不了。

我在项目中遇到过一件事:某客户用了一颗 SoC,OTP 里只烧了 128 位哈希,结果发现哈希碰撞风险太高。后来我建议他们改用 256 位,配合硬件加速引擎,才把这事摆平。

我的建议:OTP 空间很贵,别啥都往里塞。只存根公钥的哈希(256位足矣),其他证书链放 Flash,启动时逐级验证。

4.2 BootROM 安全

BootROM 是芯片上电后执行的第一段代码。它固化在掩膜 ROM 里,理论上改不了。但「改不了」不代表「攻不破」。

BootROM 常见的安全问题,我列几个典型的:

漏洞类型 风险描述 真实案例
调试接口未锁定 JTAG/SWD 在 BootROM 阶段可访问 某路由器芯片,JTAG 直读 BootROM 代码
USB 下载模式绕过 通过特定 USB 序列进入下载模式,跳过签名校验 某手机芯片,短接两个引脚直接刷机
时序攻击 签名验证耗时不同,泄露密钥信息 某 IoT 芯片,通过电源纹波分析破解
缓冲区溢出 BootROM 解析外部输入时未做边界检查 某车规芯片,通过 CAN 报文触发溢出

我曾经帮一个客户做 BootROM 安全审计,发现他们的 BootROM 在读取外部 SPI Flash 时,没有对地址范围做校验。攻击者只要在 Flash 特定位置放一段恶意数据,就能让 BootROM 跳转到任意地址执行。嗯,这种低级错误其实挺常见的。

避坑指南:我曾经见过一个团队,BootROM 里留了个「工厂测试模式」,出厂时忘了熔断 OTP 里的禁用位。结果被攻击者利用这个模式直接 dump 了整个固件。记住:所有调试接口、测试模式,量产时必须永久关闭。

4.3 U-Boot 安全加固

U-Boot 是嵌入式 Linux 世界用得最多的 bootloader。它功能强大,但攻击面也大。我见过太多设备,U-Boot 裸奔着就上线了——没有签名校验、没有环境变量保护、甚至串口都没锁。

U-Boot 安全加固,我一般按这几个维度来:

4.3.1 签名验证机制

U-Boot 从 v2016 开始支持 verified boot。核心思路是:U-Boot 本身由 BootROM 验证,然后 U-Boot 再去验证内核和设备树。

// 配置 verified boot 的关键选项
CONFIG_FIT_SIGNATURE=y
CONFIG_RSA=y
CONFIG_RSA_SOFTWARE_EXP=y
CONFIG_OF_CONTROL=y
CONFIG_SPL_FIT_SOURCE="uboot-fit.its"

签名流程大致是这样:

  1. 生成 RSA 密钥对(私钥自己保管好,公钥烧进 OTP)
  2. 用私钥对 FIT image 签名
  3. U-Boot 启动时,用 OTP 里的公钥验签
  4. 验签通过才加载内核,否则死循环或进恢复模式

关键点:公钥必须从 OTP 读取,不能从 Flash 读。否则攻击者可以替换公钥,签名校验形同虚设。

4.3.2 环境变量保护

U-Boot 的环境变量默认存在 Flash 里,明文存储。攻击者只要改一个 bootargs,就能让内核启动时挂载恶意文件系统。

我建议的做法:

  • 环境变量加密:用 AES 加密存储,密钥从 OTP 派生
  • 环境变量签名:每次写入时附带 HMAC,启动时校验完整性
  • 锁定关键变量:比如 bootcmd、bootargs,设为只读
// 环境变量加密配置示例
CONFIG_ENV_AES=y
CONFIG_ENV_AES_KEY="your-256-bit-key-here"
CONFIG_ENV_IS_IN_MMC=y
CONFIG_ENV_SIZE=0x20000

我的经验:别把加密密钥硬编码在源码里。我见过有人把密钥写在头文件里,结果代码托管平台泄露了。正确的做法是从 OTP 或安全芯片派生密钥。

4.3.3 串口与调试接口锁定

U-Boot 的串口控制台是攻击者的最爱。只要接上串口线,按个回车,就能进入 U-Boot 命令行,为所欲为。

加固措施:

  • 密码保护:进入命令行需要密码,密码不能明文存
  • 禁用危险命令:比如 sf probe、mmc write、fatload 等
  • 超时自动启动:串口无输入 3 秒后自动加载内核,不给攻击者操作时间
// 禁用危险命令的配置
CONFIG_CMD_SF=n
CONFIG_CMD_MMC=n
CONFIG_CMD_FAT=n
CONFIG_CMD_EXT4=n
CONFIG_CMD_ITEST=n

// 设置密码(哈希存储)
setenv bootdelay 3
setenv stdin_password 'sha256:xxxx...'

注意:我曾经遇到一个案例,客户禁用了所有危险命令,但忘了禁用「reset」命令。攻击者通过反复复位设备,在特定时序下触发了 BootROM 的漏洞。所以,攻击面分析要全面,不能只看 U-Boot 本身。

4.4 安全启动链的完整流程

把上面这些串起来,一个完整的安全启动链应该是这样的:

安全启动链完整流程 BootROM(信任根) OTP 存储根公钥 BootROM 验签 U-Boot U-Boot SPL(一级引导) U-Boot 主程序 U-Boot 验签内核/FIT 内核启动(安全环境) 关键说明: • 每一级只信任上一级的签名 • 公钥链必须硬件锚定 • 任何一级验签失败即停止启动 验签失败处理: • 进入恢复模式 • 记录安全事件日志

这个流程里,每一级都只信任上一级的签名结果。BootROM 信任 OTP 里的公钥,U-Boot 信任 BootROM 的验证结果,内核信任 U-Boot 的验证结果。这就是所谓的「信任链」——环环相扣,缺一不可。

总结一下:安全启动链不是某个单一技术,而是一整套从硬件到软件的信任传递机制。OTP 存根、BootROM 验签、U-Boot 加固,每一环都得做到位。我在项目中见过太多「木桶效应」——明明 BootROM 很安全,结果 U-Boot 裸奔,整个安全链直接崩了。

嗯,这一章的内容就到这。记住:安全启动链是固件安全的第一道防线,也是最后一道防线。搞砸了它,后面做再多加固都是白搭。