1. 安全启动概述:工业MCU面临的安全威胁、安全启动的定义与目标、信任根(RoT)的概念
大家好,欢迎来到这门实战课。我是你们的老朋友,一个在嵌入式安全领域摸爬滚打了十几年的工程师。今天咱们聊聊安全启动,这是整个固件保护体系的基石。说白了,如果这一步没做好,后面加再多锁也没用。
1.1 工业MCU面临的安全威胁:你的设备正在被谁盯着?
很多人觉得,工业设备嘛,藏在工厂角落里,谁没事会去攻击它?我以前也这么想,直到有一次帮客户做售后分析——一台PLC莫名其妙地执行了错误逻辑,差点把整条产线搞停。后来一查,是有人通过调试接口把篡改过的固件灌了进去。
工业MCU面临的威胁,其实比消费电子更棘手。我总结了几类最常见的:
- 固件逆向与克隆:攻击者通过读取Flash或调试接口,把你的固件dump出来,然后抄板、克隆。我在一个项目里见过,竞争对手直接拿我们的固件改了个Logo就上市了。
- 恶意固件注入:通过未锁定的JTAG/SWD接口、UART bootloader,或者利用OTA更新的漏洞,把恶意代码写进去。嗯,这就是刚才那个PLC案例的罪魁祸首。
- 物理攻击:比如电压毛刺、激光照射,让MCU跳过安全校验。听起来像科幻片?其实一套几百块的设备就能做到。
- 侧信道攻击:通过分析功耗、电磁辐射来窃取密钥。我刚开始接触这个领域时,觉得这得是国家级黑客才玩得起,后来发现,开源工具就能搞定。
核心观点:工业MCU一旦被攻破,轻则设备报废,重则产线停摆、数据泄露。安全启动,就是第一道防线。
1.2 安全启动的定义与目标:它到底在保护什么?
安全启动,说白了就是让MCU在通电后,只运行你授权的固件。任何篡改过的、非官方的代码,一律拒绝执行。
它的目标很明确,就三条:
- 完整性校验:确保固件没有被修改过。哪怕只改了一个bit,校验也得失败。
- 真实性验证:确保固件确实来自你(或你的团队),而不是攻击者伪造的。
- 执行控制:只有通过校验的代码才能运行,否则MCU就停在安全状态,或者进入恢复模式。
你可能会问:「我加个CRC校验不就行了?」嗯,我刚开始也这么想。但CRC只能检测随机错误,攻击者完全可以改了固件后重新计算CRC。所以,安全启动必须依赖非对称加密或消息认证码(MAC)。
我的经验:在工业项目中,我建议优先使用非对称签名(比如ECDSA)。因为私钥可以保存在安全的环境中,MCU里只放公钥。这样即使固件被dump,攻击者也伪造不了签名。
1.3 信任根(RoT)的概念:整个安全体系的锚点
信任根,英文叫Root of Trust,简称RoT。它是整个安全启动的起点,也是你唯一需要无条件信任的东西。
为什么需要它?你想想看,安全启动要校验固件,那谁来校验校验程序本身?如果校验代码被篡改了,那它可能永远返回「校验通过」。这就成了「贼喊捉贼」。
所以,信任根必须满足两个条件:
- 不可篡改:通常固化在ROM里,或者由硬件保护的一次性可编程(OTP)区域。
- 不可绕过:MCU上电后,第一条指令必须来自信任根,没有例外。
我见过一些设计,把信任根放在Flash里,然后用一个GPIO引脚来锁定。结果呢?攻击者只要在启动时拉低那个引脚,就能跳过校验。嗯,这种设计我称之为「掩耳盗铃」。
常见的信任根实现方式有:
| 类型 | 存储位置 | 特点 | 典型MCU |
|---|---|---|---|
| 硬件RoT | ROM + OTP | 不可修改,安全性最高 | STM32H7、i.MX RT |
| 软件RoT | Flash保护区 | 可更新,但需配合硬件保护 | 部分低端MCU |
| 外部RoT | 独立安全芯片 | 隔离性好,但增加成本 | ATECC608A |
避坑指南:我曾经在一个项目里,为了省成本,把信任根放在Flash里,只靠读保护来防止篡改。结果客户反馈,设备在极端温度下读保护失效,固件被完整dump了出来。从那以后,我再也不敢在信任根上省钱了。
1.4 安全启动的典型流程:从复位到运行
好了,理论讲完了,咱们看看实际怎么跑。一个典型的安全启动流程是这样的:
- 上电复位:MCU从复位向量中取出第一条指令,指向信任根代码(通常叫BootROM)。
- 加载公钥:信任根从OTP或一次性烧录的区域,读取你的公钥哈希。注意,这里存的是哈希,不是公钥本身,防止被替换。
- 验证Bootloader:信任根读取Flash中的Bootloader,用公钥验证它的签名。如果失败,进入错误处理(比如死循环或点亮错误灯)。
- 验证应用固件:Bootloader再验证应用固件的签名。这一步可以灵活处理,比如只验证头部,或者全量验证。
- 跳转执行:所有校验通过后,Bootloader把控制权交给应用固件。
这里有个细节:为什么分两步验证?因为Bootloader通常很小,验证快;应用固件可能很大,全量验证会拖慢启动时间。我在一个电机控制项目里,应用固件有2MB,全量验证要3秒多,客户直接投诉。后来改成只验证关键代码段,启动时间降到了200ms。
// 伪代码示例:信任根验证Bootloader
void bootrom_main(void) {
// 1. 从OTP读取公钥哈希
uint8_t expected_hash[32];
otp_read(OTP_PUBKEY_HASH_ADDR, expected_hash, 32);
// 2. 从Flash读取Bootloader的公钥
uint8_t pubkey[64];
flash_read(BOOTLOADER_PUBKEY_ADDR, pubkey, 64);
// 3. 计算公钥哈希,与OTP中的比较
uint8_t computed_hash[32];
sha256(pubkey, 64, computed_hash);
if (memcmp(expected_hash, computed_hash, 32) != 0) {
// 公钥被篡改,进入安全陷阱
secure_trap();
}
// 4. 用公钥验证Bootloader签名
uint8_t signature[64];
flash_read(BOOTLOADER_SIG_ADDR, signature, 64);
if (!ecdsa_verify(pubkey, bootloader_addr, bootloader_size, signature)) {
secure_trap();
}
// 5. 跳转到Bootloader
jump_to(bootloader_addr);
}
关键点:信任根代码本身必须是不可修改的。如果攻击者能改BootROM,那整个安全体系就崩塌了。所以,工业级MCU都会把BootROM放在只读的ROM里,出厂后无法更改。
1.5 小结与思考
这一章我们聊了三个核心问题:
- 工业MCU面临的安全威胁——逆向、注入、物理攻击,一个比一个狠。
- 安全启动的定义与目标——完整性、真实性、执行控制,缺一不可。
- 信任根的概念——它是整个安全体系的锚点,必须不可篡改、不可绕过。
你可能会问:「我的产品只是个小传感器,也需要这么复杂的安全启动吗?」嗯,我建议你换个角度想:攻击者不会因为你的设备便宜就手下留情。相反,越是大规模部署的设备,越容易被盯上。因为攻破一个,就能克隆一万个。
下一章,咱们会深入聊聊具体的签名算法和密钥管理。到时候我会分享一个我踩过的坑——用RSA签名结果把Flash撑爆了。敬请期待。