4. 通信安全:TLS/DTLS握手、证书管理、双向认证、防重放攻击、安全通道建立
通信安全,说白了就是解决两个问题:“你是谁”和“数据有没有被改过”。在OTA升级场景里,车端和云端之间跑的是敏感数据——固件包、签名、版本号。一旦通信链路被劫持,攻击者可以注入恶意固件,后果不堪设想。
我做过好几个车厂的OTA项目,发现很多团队把精力都花在升级流程上,却忽略了通信层的基础防护。结果呢?安全评审一过,漏洞一大把。今天我们就来把这块彻底讲透。
4.1 TLS与DTLS:选哪个?
先看一个基础问题:你的OTA通道用TCP还是UDP?
| 协议 | 传输层 | 适用场景 | 典型延迟 |
|---|---|---|---|
| TLS 1.2/1.3 | TCP | 固件下载、元数据同步 | 1-2 RTT(握手) |
| DTLS 1.2/1.3 | UDP | 状态上报、日志流、低带宽链路 | 0.5-1 RTT |
我个人习惯:主链路用TLS,辅助链路用DTLS。为什么?固件包必须可靠传输,TCP+ TLS天然适合。但车端上报状态、心跳、日志这些轻量数据,用UDP+ DTLS能省不少带宽和功耗。
4.2 握手流程:不只是“你好”和“证书”
TLS握手看起来简单——客户端发Hello,服务端回证书,然后密钥协商。但实际项目中,握手失败的原因千奇百怪。
我画了一张流程图,帮你理清核心步骤:
嗯,这里要注意:证书验证是握手中最耗时的环节。车端资源有限,解析完整的X.509证书链可能需要几百毫秒。我建议在握手前先缓存CA证书,减少在线验证开销。
4.3 证书管理:别让证书成为短板
证书管理是通信安全里最容易出问题的地方。我见过太多项目:证书写死在固件里、过期了没人管、吊销列表从来不更新。你想想看,如果攻击者拿到了一个过期证书,你的双向认证还有什么意义?
证书管理的核心原则:
- 证书轮换:每 1-2 年更新一次,支持 OTA 远程推送新证书
- 吊销检查:支持 OCSP Stapling 或 CRL,避免每次握手都去查吊销列表
- 证书链裁剪:只下发必要的中间证书,减少握手包大小
- 根证书预置:出厂时烧录根证书,后续只更新叶子证书
4.4 双向认证:不只是服务端验客户端
单向认证(服务端证书)只能保证你连的是真云端,但云端怎么知道你是真车?这就是双向认证的价值。
双向认证的流程:
- 服务端下发证书链,车端验证
- 车端下发自己的客户端证书,服务端验证
- 双方各自用私钥签名一段随机数,证明持有私钥
- 握手完成,建立双向信任
我建议在OTA场景中必须启用双向认证。为什么?因为攻击者可以伪造车端身份,然后请求固件包——虽然固件包有签名,但攻击者可以分析固件内容,找到漏洞。双向认证直接把这道门焊死。
4.5 防重放攻击:时间戳 + 随机数 + 序列号
重放攻击是OTA通信里最常见的攻击方式之一。攻击者截获一条合法的升级请求,然后反复发送给云端,导致车端重复下载、重复升级,甚至耗尽流量。
防重放的三个核心手段:
| 手段 | 原理 | 优缺点 |
|---|---|---|
| 时间戳 | 消息携带当前时间,服务端检查是否在窗口内 | 简单,但依赖时钟同步 |
| 随机数(Nonce) | 每次握手生成唯一随机数,服务端记录已用Nonce | 安全,但需要维护状态表 |
| 序列号 | 每条消息携带递增序列号,服务端检查单调性 | 轻量,但需要持久化存储 |
我个人习惯:组合使用时间戳 + 序列号。时间戳用于快速过滤过期消息(比如 5 秒窗口),序列号用于防止窗口内的重放。这样既保证了实时性,又不需要维护庞大的 Nonce 表。
4.6 安全通道建立:从握手到加密传输
握手完成后,TLS/DTLS 会生成一套会话密钥,用于后续的对称加密。这里要注意几个细节:
- 会话复用:TLS 支持 Session ID 或 Session Ticket,避免每次请求都重新握手。车端频繁上报状态时,这个优化能省大量时间。
- 密钥更新:长连接场景下,建议每 24 小时或每 1000 条消息更新一次密钥。TLS 1.3 原生支持密钥更新,直接调用 KeyUpdate 即可。
- 加密套件选择:推荐 TLS_AES_128_GCM_SHA256(TLS 1.3)或 ECDHE-ECDSA-AES128-GCM-SHA256(TLS 1.2)。避免使用 CBC 模式,容易受到 Padding Oracle 攻击。
最后,安全通道建立后,所有 OTA 相关数据——固件包、签名、版本号、状态上报——都必须走这个加密通道。不要因为“数据量小”就跳过加密,攻击者不会嫌数据少。