2、刷写安全威胁分析:中间人攻击、重放攻击、刷写包篡改、刷写中断风险
好,咱们进入第二个核心话题——刷写安全威胁分析。
说实话,很多工程师觉得OTA刷写嘛,不就是把文件发下去、写进Flash就完事了?我见过太多项目,前期只关注刷写速度、压缩率,结果在安全测试阶段被打得满地找牙。 今天我就把四种最常见的威胁掰开揉碎了讲,这些都是我在实车调试中真刀真枪碰过的坑。
2.1 中间人攻击:你的刷写包被“偷听”了
中间人攻击,简称MITM。说白了,就是攻击者悄悄站在你车机和云端之间,把通信内容全看了个遍。
为什么会发生? 很多老车型的刷写链路用的是HTTP或者不加密的TCP。攻击者只要连上同一个Wi-Fi热点,或者通过OBD口接入CAN网络,就能轻松抓包。
攻击流程:
- 攻击者伪装成云端服务器,跟车机建立连接。
- 同时伪装成车机,跟云端建立连接。
- 所有刷写数据都经过攻击者中转,他不仅能看,还能改。
我记得有一次帮客户做安全审计,他们用的是TLS 1.0,证书还是自签名的。我拿Wireshark抓了五分钟包,直接看到了刷写包的明文内容。嗯,这跟没穿衣服上街没啥区别。
我的建议:
- 必须使用TLS 1.2以上,证书链要完整验证。
- 车机端要内置根证书,拒绝所有未认证的连接。
- 刷写通道最好做双向认证——车机验证云端,云端也要验证车机。
2.2 重放攻击:同一个包,反复刷
重放攻击,攻击者把之前抓到的合法刷写包,原封不动地再发一次。
你想想看,如果攻击者在你刷写ECU时录下了某个关键数据帧,然后在你下次启动车辆时重放这个帧,会发生什么?轻则ECU进入错误状态,重则直接刷入旧版本固件,把安全补丁全给覆盖了。
我在项目中遇到过一起真实案例:某Tier1的刷写工具没有做防重放,攻击者把刷写过程中的“刷写完成”确认帧重放了一遍,结果ECU误以为刷写成功,直接跳过了校验步骤。最后车机黑屏,只能返厂维修。
避坑指南:
- 每个刷写包必须带时间戳或单调递增的序列号。
- ECU端要记录最后一次成功刷写的序列号,拒绝所有小于等于该值的包。
- 我曾经见过一个方案,用刷写会话ID+随机数做防重放,效果不错,但要注意随机数生成器的质量。
2.3 刷写包篡改:改一个字节,整辆车瘫痪
刷写包篡改,攻击者把合法的刷写文件改了,比如植入恶意代码、修改关键参数。
这种攻击最可怕的地方在于——你根本不知道固件被改了。ECU刷进去之后,表面上一切正常,但某个特定条件下就会触发恶意行为。比如刹车时偷偷关掉ABS,或者加速时限制发动机功率。
怎么防?核心就一句话:签名验证。
// 伪代码示例:刷写包签名验证流程
uint8_t* firmware_data; // 刷写包数据
uint32_t data_len; // 数据长度
uint8_t* signature; // 签名值
uint32_t sig_len; // 签名长度
// 1. 提取刷写包中的公钥证书
Certificate cert = extract_certificate(firmware_data);
// 2. 验证证书链(根证书预置在ECU中)
if (!verify_cert_chain(cert, root_cert)) {
return ERROR_CERT_INVALID;
}
// 3. 用公钥验证签名
if (!verify_signature(firmware_data, data_len, signature, cert.public_key)) {
return ERROR_SIGNATURE_MISMATCH;
}
// 4. 签名验证通过,允许刷写
return SUCCESS;
我个人习惯用ECDSA签名,密钥长度短、性能好。RSA也行,但2048位以下的就别用了,太容易破解。
关键点:
- 签名必须覆盖整个刷写包,包括头部和元数据。
- 公钥证书要预置在ECU的安全存储区,不能从外部传入。
- 我曾经见过一个方案,签名只覆盖了固件数据,没覆盖刷写命令头。攻击者把命令头里的目标地址改了,固件刷到了错误分区,直接变砖。
2.4 刷写中断风险:刷到一半断电了怎么办?
刷写中断,可能是最让人头疼的问题。不是攻击者干的,但后果比攻击还严重。
你想想看,ECU正在擦写Flash,突然断电了。这时候Flash里可能一半是新固件、一半是旧固件,甚至擦了一半还没写。下次上电,ECU根本跑不起来。
我遇到过最惨的一次: 某主机厂在做批量OTA升级,结果服务器压力太大,导致部分车辆的刷写会话超时中断。第二天早上,售后电话被打爆了——200多辆车无法启动。
怎么解决?核心策略是双分区备份 + 回滚机制。
| 分区 | 作用 | 刷写时的状态 |
|---|---|---|
| Bank A(当前运行区) | 存放当前正在运行的固件 | 刷写期间保持不变 |
| Bank B(备份/升级区) | 存放新固件或旧固件备份 | 刷写目标区域 |
| Bootloader(引导区) | 负责启动和回滚决策 | 只读,永不修改 |
刷写流程是这样的:
- 新固件先写入Bank B。
- 写入完成后,校验Bank B的完整性(CRC/SHA256)。
- 校验通过,更新启动标志,指向Bank B。
- 重启,从Bank B启动。
- 如果启动失败,Bootloader检测到异常,自动切回Bank A。
注意:
- Bootloader必须足够简单、稳定,不能依赖任何外部存储。
- 启动标志要存储在独立的安全存储区,比如OTP或eFuse。
- 我曾经见过一个设计,启动标志存在Flash里,结果刷写中断时Flash数据损坏,启动标志也丢了,彻底变砖。
2.5 四种威胁的防护优先级
最后,我按自己的经验排个优先级。如果资源有限,先搞定前面的:
| 威胁类型 | 防护优先级 | 核心防护手段 | 我踩过的坑 |
|---|---|---|---|
| 刷写包篡改 | 最高 | 签名验证 | 签名没覆盖命令头,导致地址被篡改 |
| 刷写中断 | 高 | 双分区 + 回滚 | 启动标志存在Flash里,数据损坏后变砖 |
| 中间人攻击 | 中 | TLS + 双向认证 | 自签名证书,抓包直接看明文 |
| 重放攻击 | 中 | 时间戳/序列号 | 刷写完成帧被重放,跳过校验 |
嗯,这四种威胁,每一个都能让你的OTA项目翻车。但别怕,后面几章我会详细讲怎么落地这些防护策略。记住一句话:安全不是加个锁,而是设计一套完整的防御体系。