一、安全启动概述:MCU 为什么需要一把“锁”

大家好,我是你们的讲师。今天咱们开始聊 MCU 安全启动。说实话,我入行头几年做嵌入式,压根没想过“安全”这回事。那时候觉得,一个单片机,跑个裸机程序,谁没事来攻击你?直到有一次,我在一个工业控制项目里,发现现场设备被人用烧录器直接读走了固件,还改了启动参数……嗯,从那以后,我再也不敢轻视安全启动了。

1.1 什么是 MCU 安全启动?

安全启动,说白了就是让 MCU 上电后,只运行经过你授权的、没有被篡改过的固件。它不是一个功能,而是一套从 BootROM 到应用层的信任链。

我习惯把它拆成三个步骤:

  1. 验证启动代码的完整性——检查代码有没有被改过。
  2. 验证启动代码的合法性——检查代码是不是来自你(签名验证)。
  3. 逐级信任传递——BootROM 验证 Bootloader,Bootloader 验证应用固件。

你想想看,如果第一步就被人跳过了,后面所有安全措施都是白搭。

核心概念:信任根(Root of Trust, RoT)

信任根通常是固化在 MCU 内部 ROM 里的一段不可修改的代码。它是整个安全启动的起点,也是你唯一能无条件信任的东西。我在 STM32L5 和 NXP i.MX RT 系列上都见过类似的实现,原理大同小异。

1.2 为什么需要签名验证?

光有完整性检查够吗?不够。完整性检查(比如 CRC、SHA256)只能告诉你固件有没有被改过,但它没法告诉你这个固件是不是你写的。攻击者完全可以自己写一个恶意固件,算好哈希值,然后刷进去。完整性检查照样通过。

签名验证解决的就是这个问题。它用非对称加密算法(比如 ECDSA、RSA),让你用私钥签名固件,MCU 用公钥验证签名。只要私钥不泄露,攻击者就伪造不了合法固件。

验证方式 能防篡改? 能防伪造? 典型算法
CRC 校验 弱(可碰撞) 否 CRC32
哈希校验 强(SHA256) 否 SHA-256
签名验证 强 是 ECDSA、RSA

我的经验: 签名验证的坑往往不在算法本身,而在密钥管理。我曾经见过一个团队把私钥直接硬编码在编译脚本里,还上传到了 Git 仓库……结果可想而知。私钥必须离线保存,最好用 HSM(硬件安全模块)管理。

1.3 常见的安全威胁模型

做安全启动,你得先知道敌人是谁。我根据实际项目经验,把威胁分成三类:

1.3.1 物理攻击

攻击者手里有设备,甚至能拆开外壳。常见手段包括:

  • JTAG/SWD 调试接口攻击:直接通过调试接口读取 Flash 或篡改内存。
  • 电压/时钟毛刺攻击:通过电源噪声或时钟抖动,让 CPU 跳过安全校验指令。
  • 探针攻击:用微探针直接读取总线上的数据。

我记得有一次做渗透测试,对方用电压毛刺攻击,硬是让我们的 Bootloader 跳过了签名验证函数。从那以后,我所有项目都加了电压检测和循环冗余校验。

1.3.2 固件篡改

这是最常见的攻击方式。攻击者通过以下途径修改固件:

  • OTA 更新劫持:在固件下载过程中替换数据包。
  • Flash 编程接口:通过 UART、SPI、USB 等接口直接写入恶意固件。
  • 供应链攻击:在生产环节或物流环节替换芯片/固件。

避坑指南: 我曾经遇到一个客户,OTA 更新只做了 CRC 校验,没做签名验证。结果攻击者伪造了一个更新包,导致现场 2000 多台设备全部变砖。事后排查发现,攻击者只是用了一个简单的中间人攻击工具。所以,OTA 更新必须做签名验证,这是底线。

1.3.3 回滚攻击

攻击者把固件版本降级到有漏洞的旧版本,然后利用已知漏洞入侵系统。比如:

  • 旧版本 Bootloader 有缓冲区溢出漏洞。
  • 旧版本固件的加密算法已被破解。
  • 旧版本固件关闭了某些安全功能。

防止回滚攻击的方法很简单:在固件头里加入版本号,并在 Bootloader 中强制检查版本号只能递增,不能递减。

1.4 安全启动的信任链模型

下面这张图是我自己画的,展示了典型的 MCU 安全启动信任链。你可以看到,信任是从 BootROM 开始,一级一级传递下去的。

MCU 安全启动信任链 MCU 安全启动信任链 BootROM(信任根) Bootloader (验证签名 + 完整性) 应用固件 (验证签名 + 版本号) 运行时安全 (MPU/TrustZone/看门狗) 每一级验证失败,MCU 必须进入安全错误状态(死循环、复位或锁定)

这个模型里,每一级都只信任上一级。如果 BootROM 验证 Bootloader 失败,系统直接锁死。如果 Bootloader 验证应用固件失败,同样不能启动。这就是“信任链”的含义——环环相扣,一个断了,整个链就断了。

1.5 安全启动的典型流程

我整理了一个标准的安全启动流程,你可以对照自己的项目看看少了哪一步:

  1. 上电复位:CPU 从 BootROM 开始执行。
  2. 读取安全配置:检查 Option Bytes、efuse 或 OTP 区域,确认安全等级。
  3. 加载 Bootloader 头:读取固件头中的签名、哈希、版本号等信息。
  4. 验证 Bootloader 签名:用公钥解密签名,与固件哈希比对。
  5. 跳转到 Bootloader:验证通过后,清除敏感数据,跳转执行。
  6. Bootloader 验证应用固件:重复步骤 3-4,验证应用固件。
  7. 启动应用:验证通过后,跳转到应用入口。

一个小技巧: 我习惯在 Bootloader 里加一个“回滚计数器”,每次成功启动后递增。如果连续 N 次启动失败(比如验证失败),就强制进入恢复模式,等待 OTA 更新。这样即使固件刷坏了,设备也不会变砖。

1.6 本章小结

安全启动不是可选项,而是嵌入式设备的底线。你想想看,如果连自己写的固件都保护不了,那设备就跟裸奔没什么区别。这一章我们讲了三个核心点:

  • 安全启动的本质:建立从 BootROM 到应用层的信任链。
  • 签名验证的必要性:完整性检查防不了伪造,签名验证才能。
  • 三大威胁模型:物理攻击、固件篡改、回滚攻击,每个都要防。