2、刷写安全威胁分析:中间人攻击、重放攻击、刷写包篡改、刷写中断风险

好,咱们进入第二个核心话题——刷写安全威胁分析。

说实话,很多工程师觉得OTA刷写嘛,不就是把文件发下去、写进Flash就完事了?我见过太多项目,前期只关注刷写速度、压缩率,结果在安全测试阶段被打得满地找牙。 今天我就把四种最常见的威胁掰开揉碎了讲,这些都是我在实车调试中真刀真枪碰过的坑。

2.1 中间人攻击:你的刷写包被“偷听”了

中间人攻击,简称MITM。说白了,就是攻击者悄悄站在你车机和云端之间,把通信内容全看了个遍。

为什么会发生? 很多老车型的刷写链路用的是HTTP或者不加密的TCP。攻击者只要连上同一个Wi-Fi热点,或者通过OBD口接入CAN网络,就能轻松抓包。

攻击流程:

  1. 攻击者伪装成云端服务器,跟车机建立连接。
  2. 同时伪装成车机,跟云端建立连接。
  3. 所有刷写数据都经过攻击者中转,他不仅能看,还能改。

我记得有一次帮客户做安全审计,他们用的是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(引导区) 负责启动和回滚决策 只读,永不修改

刷写流程是这样的:

  1. 新固件先写入Bank B。
  2. 写入完成后,校验Bank B的完整性(CRC/SHA256)。
  3. 校验通过,更新启动标志,指向Bank B。
  4. 重启,从Bank B启动。
  5. 如果启动失败,Bootloader检测到异常,自动切回Bank A。

注意:

  • Bootloader必须足够简单、稳定,不能依赖任何外部存储。
  • 启动标志要存储在独立的安全存储区,比如OTP或eFuse。
  • 我曾经见过一个设计,启动标志存在Flash里,结果刷写中断时Flash数据损坏,启动标志也丢了,彻底变砖。

2.5 四种威胁的防护优先级

最后,我按自己的经验排个优先级。如果资源有限,先搞定前面的:

威胁类型 防护优先级 核心防护手段 我踩过的坑
刷写包篡改 最高 签名验证 签名没覆盖命令头,导致地址被篡改
刷写中断 双分区 + 回滚 启动标志存在Flash里,数据损坏后变砖
中间人攻击 TLS + 双向认证 自签名证书,抓包直接看明文
重放攻击 时间戳/序列号 刷写完成帧被重放,跳过校验

嗯,这四种威胁,每一个都能让你的OTA项目翻车。但别怕,后面几章我会详细讲怎么落地这些防护策略。记住一句话:安全不是加个锁,而是设计一套完整的防御体系。