MAVLink 安全通信系列(7):威胁模型与安全评估
返回系列总目录。
本系列补充篇。前面讲"怎么补",这一篇反过来问"不补会怎样":把攻击者是谁、 站在哪、能干什么先摆清楚,再逐个演示窃听、篡改、伪造 / 中间人、重放 四类攻击,最后对照看这套 X.509 + AES-GCM 方案各自挡住了谁、还挡不住谁。
1. 为什么先建威胁模型
"要安全"是句空话,"防谁、防到什么程度"才是工程问题。威胁模型(threat model)就是回答三个问题:
- 攻击者是谁(能力多大、动机是什么);
- 他在哪(能碰到链路的哪个位置);
- 他想干什么(偷看、改数据、冒充、还是让链路瘫痪)。
建完模型,才知道每一刀该花在哪。MAVLink 链路的攻击面如下:
flowchart LR
UAV["飞控 PX4"] -- "串口 / 数传链路" --> GCS["地面站 QGC"]
E1["攻击者 A<br/>被动监听(并接 / 截获射频)"] -.->|窃听| LINK1["链路"]
E2["攻击者 B<br/>主动注入(假 GCS)"] -.->|伪造 / 篡改| LINK2["链路"]
E3["攻击者 C<br/>中间人(截断转发)"] -.->|双向欺骗| LINK3["链路"]
GCS --- LINK1
GCS --- LINK2
GCS --- LINK32. 威胁模型:攻击者画像与能力
| 维度 | 攻击者 A(窃听者) | 攻击者 B(注入者) | 攻击者 C(中间人) |
|---|---|---|---|
| 位置 | 链路旁(被动) | 链路旁(主动发) | 链路中间(截断 + 转发) |
| 能力 | 只读不写 | 可发任意字节 | 可读、可改、可伪造双向流量 |
| 手段 | 并接串口、截获数传射频 | 注入假消息、重放旧包 | 冒充两端、双向转发 |
| 目标 | 位置 / 姿态 / 航点 | 下发假指令、干扰飞行 | 完全接管通信 |
明文 MAVLink 下,三个攻击者的门槛都极低:协议是公开的、字段是固定的、CRC 可以重算。下面逐个演示。
3. 演示一:窃听(无机密性)
攻击:串口 / 数传是明文,攻击者并接一根线或截获射频,把字节流按 MAVLink 帧结构一解析,就能读出全部飞行数据。以姿态消息 ATTITUDE 为例:
明文链路里抓到的 ATTITUDE(可直接读):
FD 1C 00 00 00 01 01 00 00 00 │ <roll/time_pitch/pitch/time_yaw/yaw/...>
└─ 明文字段,逐字节可解出 roll/pitch/yaw任何拿到链路的人都能还原出实时位置、姿态角、GPS 坐标、航点、任务——这是 最直观的泄露,甚至不需要"破解"任何东西。
防护:AES-GCM 加密后,payload 变成密文,但攻击者仍可看到明文 MAVLink header(包括 msgid 等路由字段)、帧长、时序和通信频率:
加密后抓到的 ATTITUDE(读不出姿态):
FD 1C 02 00 00 01 01 00 00 00 │ <28 字节密文 payload> │ CRC │ nonce(12) │ tag(16)
└─ 无会话密钥,解不出 roll/pitch/yaw对应验证:
test_aes_gcm里"带 AAD 的向量"确认了部分 header 字段作为 AAD 参与认证、 payload 被加密;example里 GCS 打印的ATTITUDE ... (decrypted)表明密文 只有用协商密钥才能解开。
4. 演示二:篡改(无完整性)
攻击:明文链路上,攻击者不仅能看,还能改——比如把一条 COMMAND_LONG 里的参数改掉。因为 CRC 只是检错(防传输误码),攻击者可以 同时重算 CRC,让改动"看起来合法":
攻击者截获:COMMAND_LONG disarm(上锁) → 改成 arm(解锁) → 重算 CRC → 转发
结果:地面站明明下发"上锁",飞控收到的却是"解锁"官方 MAVLink v2 signing 能发现这种篡改(SHA-256 签名对不上),但发现≠ 阻止:它仍不加密,也识别不了"这条消息是谁发的"。
防护:AES-GCM 标签能拒绝对密文或已纳入 AAD 字段的篡改。但当前实现只把 incompat_flags、compat_flags、seq、sysid、compid 纳入 AAD,未认证 len 与 msgid;CRC 可以被攻击者重算。因此当前方案不能声称完整 MAVLink 帧头都受 GCM 保护。在把未认证头字段作为安全决策依据前,必须先修订并统一双端 的 AAD 格式。
GOT_AES_TAG:读完 16 字节 tag → mavlink_aes_gcm_decrypt()
→ 重算 tag 并常量时间比对 → 失败:清零 payload,当坏帧丢弃对应验证:
test_aes_gcm的"篡改 AAD 必须被拒绝"用例;test_handshake的 "篡改证书 / 签名 / 临时点""错钥 GCM 拒绝"用例。第 3 篇有句话点破本质: 只有密文与当前 AAD 验证通过后,payload 才可交给应用层;这不代表完整 header 已认证,也不代表接收端做了 anti-replay。
5. 演示三:伪造 / 中间人(无真实性)
攻击:这是最危险的一类。明文链路没有"身份"概念,攻击者可以直接冒充 地面站下发命令,或站在中间截断两端、双向转发并篡改(中间人)。
对握手型方案,中间人最想干的是密钥替换:GCS 和 UAV 各自以为在跟对方 协商,实际都跟中间人各自协商,中间人拿到两把会话密钥,解密→看→改→重新加密 转发,两端毫无察觉。
sequenceDiagram
participant G as 真 GCS
participant M as 中间人 M
participant U as 真 UAV
Note over M: 截获真 GCS 的 CLIENT_HELLO
M->>U: 用自己的临时公钥发 HELLO
U->>M: SERVER_HELLO + UAV 证书(UAV 以为在跟 GCS 谈)
M->>G: 伪造 SERVER_HELLO(GCS 以为在跟 UAV 谈)
Note over G,M,U: 两端各自和 M 建立"安全"通道,M 解密一切流量握手防护:双向证书认证与 transcript 签名可阻止没有合法私钥的中间人替换 握手公钥。但证书是否被撤销、身份是否对应预期设备/sysid,取决于验证策略; 当前实现不做在线吊销检查或 sysid 绑定。建立会话后两端共用同一把 GCM 密钥, 因此任一端都能产生该会话下有效的双向标签,业务帧标签本身不能证明具体发送方。 两个握手层面的关键机制:
- 证书验签:中间人拿不到合法设备的私钥,无法为"它冒充的 GCS"签出 一份被 UAV 的 CA 公钥点验过的证书,也过不了 CA 验签这关;
- 签名自证:即便中间人把偷听来的合法证书重放给对端(证书是公开 数据、可复制),也过不了 ECDSA 签名自证这关——因为它没有证书对应的私钥。
这正是第 4 篇强调的"验证书 + 签名自证两步缺一不可":证书能复制,私钥 不能复制。
对应验证:
test_x509的"换错 CA 的证书被拒";test_handshake的"篡改签名/ 临时点被拒"。第 5 篇的 transcript 摘要还保证:中间人只要改了任意一个握手 字节,双方 VERIFY/FINISHED 校验必失败,握手终止。
6. 演示四:重放(无新鲜性)
攻击:攻击者录下一条合法消息,稍后再原样重放。比如录下"上锁"命令,等 飞机复飞后再重放一次,就可能造成意外上锁;或录下旧的心跳 / 姿态伪造"它还 活着"。
当前实现并未完整挡住业务帧重放:
- 帧级 nonce:nonce 供 GCM 派生密钥流和标签使用;当前接收端不保存已见 nonce,也没有序号窗口。攻击者原样重放同一会话中的合法密文,标签仍会通过, 应用层可能再次处理该消息;
- 跨会话:新握手在强随机源正常时会派生新密钥,因此旧会话密文通常不能在新 会话下验证通过;这不能代替同一会话内的 anti-replay;
- 握手记录:握手状态机对部分重复记录做去重/幂等处理,但这不等于业务帧 防重放。
对应验证:
test_handshake的重复CLIENT_HELLO用例测试握手重传幂等性;它 不是业务消息 anti-replay 测试。生产系统需定义消息新鲜性规则,例如认证的单调 计数器、每方向独立序列号和接收端重放窗口,并规定重启/掉电后的状态恢复策略。
7. 防护后的对比:一份总账
| 攻击 | 明文 MAVLink | v2 signing | 本方案(X.509 + AES-GCM) |
|---|---|---|---|
| 窃听 | ❌ 全暴露 | ❌ 仍明文 | ⚠️ payload 加密;header/流量元数据仍可见 |
| 篡改 | ❌ 可重算 CRC | ⚠️ 认证可检测篡改,不加密 | ⚠️ GCM 保护密文与当前 AAD;len/msgid 未认证 |
| 伪造身份 | ❌ 随意冒充 | ⚠️ 共享密钥持有者可签名,不能区分身份 | ⚠️ 握手期验证 CA 证书和私钥持有;无吊销检查及 sysid 绑定 |
| 中间人 | ❌ 无法察觉 | ⚠️ 不提供握手身份认证 | ⚠️ 握手认证可阻止公钥替换;受 CA 信任策略与实现边界约束 |
| 重放 | ❌ 可重放 | ⚠️ 依赖时间戳窗口与状态 | ❌ 当前业务帧没有 anti-replay 窗口 |
| 前向保密 | — | — | ⚠️ ECDHE 提供设计基础;依赖安全随机源、临时密钥清除和正确实现 |
这些机制降低了特定威胁,但不能据此说"只有合法两端才能改动流量":当前双向 复用的会话密钥允许任一持有方生成有效认证标签;还缺业务帧 anti-replay 与完整 头部认证。
8. 依然存在的风险与边界
安全不是非黑即白。这套方案仍有明确边界(第 6 篇安全检查清单):
- 无 sysid 身份绑定:任何同 CA 签发的证书都能在任何 sysid 上通过认证 (机群成员模型)。单机强绑定需把设备 ID 写进证书 CN/SAN 再与 sysid 比对;
- 无 CRL/OCSP 在线吊销:私钥泄露的设备在 CA 轮换前仍被信任;
- 有效期默认跳过:无时钟时无法判定证书是否过期,建议 GCS 对时后提供
now_unix回调; - 随机 nonce 风险:碰撞概率随每密钥消息量平方增长;应设置数据量上限并 定期 rekey;
- 旁路攻击不在此列:物理侵入、固件被改、随机源被污染等是另一层威胁 (生产必须使用熵源支持的 CSPRNG/DRBG,见第 6 篇安全检查清单)。
- 可用性与流量分析:认证加密不能阻止干扰、丢包、拥塞或设备断电;明文头和 包长/时序仍会泄漏通信行为。
理解这些边界,才能既"用得安全",也"知道什么时候该换更强的手段"。
补充排障见《常见问题与排障》,按编译配置、 证书校验、握手状态和运行环境分类查找。
