ESC
输入关键词搜索文章标题和内容

AIOT设备云端通信:三大协议对比、安全认证与数据格式

本文由 linuxROS 整理发布,首发于 linuxros.cn,转载请注明出处。

AIOT设备云端通信:三大协议对比、安全认证与数据格式

导读:AIOT设备云端通信涉及三个核心问题:用什么协议传、用什么格式表达、怎么证明"我是正品"。本文用流程图讲透HTTP/WebSocket/MQTT三种协议的选择逻辑,以及签名认证、Token认证、MD5/HMAC的核心机制与防key泄露策略。


一、三大协议对比

协议 通信模型 适用场景 资源开销
HTTP/HTTPS 请求-响应 控制指令、配置下发 中等
WebSocket 双向长连接 实时语音、即时控制 较低
MQTT 发布-订阅 海量设备上报、状态推送 极低

1.1 HTTP/HTTPS:请求-响应模型

设备发一个请求,服务器回一个响应,连接关闭。HTTP简单可靠,HTTPS(TLS加密)保证传输安全。

flowchart LR DEV["设备"] -->|"POST /api/device/report"| CLOUD["云端服务器"] CLOUD -->|"200 OK<br/>JSON响应"| DEV style DEV fill:#E3F2FD,stroke:#1976D2 style CLOUD fill:#E8F5E9,stroke:#388E3C

优点:简单、易调试、有大量现成工具(CURL/Postman)
缺点:每次新建连接开销大,不适合高频上报

1.2 WebSocket:双向长连接

一次握手建立持久连接,之后双方随时可以互相发消息,无需重复建立连接。

flowchart LR DEV["设备"] <==>|"WebSocket长连接<br/>双向实时"| CLOUD["云端服务器"] style DEV fill:#E3F2FD,stroke:#1976D2 style CLOUD fill:#E8F5E9,stroke:#388E3C

优点:双向实时、连接复用、延迟低
缺点:需要心跳保活,复杂度高于HTTP

1.3 MQTT:发布-订阅模型

设备不是直接给云端发消息,而是"发布"到某个主题(Topic),云端"订阅"这个主题即可收到。设备也可以"订阅"控制主题来接收指令。

flowchart TB subgraph 发布者["发布者"] D1["设备A<br/>发布: /home/temp"] D2["设备B<br/>发布: /home/humidity"] end subgraph Broker["🟢 MQTT Broker(消息中枢)"] BR["消息代理<br/>接收并转发主题消息"] end subgraph 订阅者["订阅者"] S1["手机App<br/>订阅: /home/temp"] S2["Web控制台<br/>订阅: /home/#"] end D1 -->|"发布"| BR D2 -->|"发布"| BR BR -->|"转发"| S1 BR -->|"转发"| S2 style D1 fill:#E3F2FD,stroke:#1976D2 style D2 fill:#E3F2FD,stroke:#1976D2 style BR fill:#FFF8E1,stroke:#F57C00 style S1 fill:#E8F5E9,stroke:#388E3C style S2 fill:#E8F5E9,stroke:#388E3C

MQTT三个QoS等级:

QoS等级 送达保证 开销 适用场景
QoS 0 最多一次(发完即丢) 最低 传感器高频上报,丢一批无所谓
QoS 1 至少一次(有重传) 中等 重要数据,不能丢但可重复
QoS 2 恰好一次(四次握手) 最高 计费数据,必须精确

优点:海量设备解耦、消息持久化(Broker存历史)、QoS保证
缺点:需要Broker服务器,协议有一定学习成本

1.4 协议选择决策树

flowchart TB START{"业务场景"} START --> C{"一对多<br/>设备广播?"} C -->|"是"| MQTT["MQTT<br/>发布-订阅"] C -->|"否"| R{"需要实时双向<br/>语音/即时控制?"} R -->|"是"| WS["WebSocket<br/>双向长连接"] R -->|"否"| HTTP["HTTP/HTTPS<br/>请求-响应"] HTTP -->|"加密"| HTTPS["HTTPS<br/>TLS加密"] style START fill:#E3F2FD,stroke:#1976D2 style MQTT fill:#FFF8E1,stroke:#F57C00 style WS fill:#E8F5E9,stroke:#388E3C style HTTP fill:#E3F2FD,stroke:#1976D2 style HTTPS fill:#E3F2FD,stroke:#1976D2

二、数据传输格式对比

2.1 常见数据格式

格式 结构 大小 解析速度 适用场景
JSON 键值嵌套 大 慢 调试、文本、配置
CBOR 二进制标签 小 中 资源受限设备、窄带宽
Protobuf IDL预定义 极小 快 高性能、跨语言、协议升级
flowchart TB subgraph JSON["🔵 JSON(文本)"] J1["key: value<br/>temp: 25.5<br/>humidity: 60"] end subgraph CBOR["🟡 CBOR(二进制)"] C1["D8 65 18 23 64..." 压缩二进制编码] end subgraph Protobuf["🟢 Protobuf(二进制)"] P1["字段1=25<br/>字段2=60"] end style JSON fill:#E3F2FD,stroke:#1976D2 style CBOR fill:#FFF8E1,stroke:#F57C00 style Protobuf fill:#E8F5E9,stroke:#388E3C

实测对比(同一条温湿度数据):
- JSON:52字节,解析需 ~50μs
- CBOR:18字节,解析需 ~10μs
- Protobuf:9字节,解析需 ~3μs

来自 linuxros.cn · linuxROS

2.2 开源库推荐

协议/格式 C/C++ Python JavaScript Arduino
HTTP/HTTPS libcurl requests axios HttpClient
WebSocket libwebsockets websockets ws / socket.io WebSocketClient
MQTT Eclipse Paho C paho-mqtt mqtt.js PubSubClient
JSON cJSON / json-c json JSON.parse ArduinoJson
Protobuf protobuf-c protobuf protobufjs nanopb
CBOR libcbor cbor cbor-js ArduinoCBOR

三、安全认证机制

3.1 为什么不能直接传key?

设备把secret直接放网络上传,等于把密码写在额头上——中间人攻击(MITM)可以轻松截获。解决方案:签名代替明文、key留在本地不外传。

3.2 MD5签名认证(简单但有缺陷)

MD5对消息内容计算摘要,服务器用同样方法验签。但MD5直接做签名已被证明不安全(碰撞攻击),仅适合内部快速实现,生产环境推荐HMAC-SHA256。

flowchart TB subgraph 设备端["🔵 设备端"] D1["原文消息"] --> D2["MD5(原文)<br/>生成32位摘要"] D2 --> D3["拼接: 原文+摘要"] D3 --> D4["发送完整包<br/>原文+MD5摘要"] end subgraph 云端["🟢 云端"] C1["收到完整包"] --> C2["提取摘要<br/>再次MD5(原文)"] C2 --> C3{"两次摘要<br/>相等?"} C3 -->|"是"| C4["验证通过"] C3 -->|"否"| C5["丢弃请求<br/>签名不匹配"] end D4 -->|"网络传输"| C1 style D1 fill:#E3F2FD,stroke:#1976D2 style D2 fill:#FFF8E1,stroke:#F57C00 style D4 fill:#FFF8E1,stroke:#F57C00 style C3 fill:#FFF8E1,stroke:#F57C00 style C4 fill:#E8F5E9,stroke:#388E3C style C5 fill:#FFEBEE,stroke:#D32F2F

MD5的问题:原文+MD5(原文)一起发,攻击者截获后可替换原文并重新计算MD5。MD5已被破解,不应用于安全认证。

3.3 HMAC签名认证(防key泄露的核心方案)

HMAC的核心改进:用secretKey对"原文"做哈希,而不是对"原文+摘要"做哈希。关键在于secretKey从不走网络,云端和设备各有一份。

flowchart TB subgraph 设备端["🔵 设备端"] D1["消息M"] --> D2["HMAC-SHA256<br/>K(secretKey) + M"] D2 --> D3["得到签名S"] D3 --> D4["发送: M + S<br/>注意:K不发送!"] end subgraph 云端["🟢 云端"] C1["收到: M + S"] --> C2["用存储的K<br/>重新计算HMAC"] C2 --> C3["得到 S'"] C3 --> C4{"S == S'?"} C4 -->|"是"| C5["验证通过"] C4 -->|"否"| C6["拒绝<br/>消息被篡改"] end D4 -->|"M+S走网络<br/>K永不离开本地"| C1 style D1 fill:#E3F2FD,stroke:#1976D2 style D2 fill:#FFF8E1,stroke:#F57C00 style D3 fill:#FFF8E1,stroke:#F57C00 style C4 fill:#FFF8E1,stroke:#F57C00 style C5 fill:#E8F5E9,stroke:#388E3C style C6 fill:#FFEBEE,stroke:#D32F2F

为什么HMAC安全:
- secretKey只存在于设备和云端,网络传输的是M(原文)+S(签名),攻击者没有Key无法伪造签名
- 即使攻击者看到S,也无法反推出K(哈希的单向性)
- 配合时间戳(timestamp)可防止重放攻击

3.4 Token认证(短期凭证)

Token是云端颁发给设备的"临时通行证",有过期时间。比直接把secret放网络上安全得多。

flowchart TB subgraph 认证阶段["🔵 阶段一:申请Token"] A1["设备发送: deviceId<br/>+ 签名(secretKey)"] A1 --> A2["云端验签通过"] A2 --> A3["生成JWT Token<br/>含: deviceId + 有效期"] A3 --> A4["返回Token给设备"] end subgraph 使用阶段["🟢 阶段二:使用Token"] B1["设备发送请求<br/>Header: Authorization: Token"] B1 --> B2["云端验证Token签名<br/>检查未过期"] B2 --> B3{"有效?"} B3 -->|"是"| B4["执行业务逻辑"] B3 -->|"否"| B5["401 Unauthorized"] end subgraph 过期处理["🟡 Token过期后"] B4 -.->|"Token过期"| A1 end style A1 fill:#E3F2FD,stroke:#1976D2 style A3 fill:#FFF8E1,stroke:#F57C00 style A4 fill:#E8F5E9,stroke:#388E3C style B2 fill:#FFF8E1,stroke:#F57C00 style B4 fill:#E8F5E9,stroke:#388E3C style B5 fill:#FFEBEE,stroke:#D32F2F

JWT Token结构:Header.Payload.Signature(三段点分隔)
- Header:算法类型(HS256/RSA)
- Payload:deviceId、过期时间、权限
- Signature:用服务器端Key对前两段的签名

3.5 实际IoT平台签名方案(阿里云/华为云/OneNET)

三大云平台均采用HMAC + 时间戳防重放的标准方案:

flowchart TB subgraph 签名要素["🟡 参与签名的要素"] T1["version<br/>签名版本号"] T2["res<br/>访问资源路径"] T3["et<br/>过期时间戳"] T4["method<br/>签名算法(sha1/sha256)"] T5["keyId<br/>密钥唯一标识"] end subgraph 签名过程["🔵 设备端签名"] S1["拼接字符串:<br/>et + method + res + version"] S2["HMAC-SHA256<br/>base64(key) + 字符串"] S3["得到签名sign"] S4["拼接Authorization:<br/>keyId=...&et=...&sign=..."] end subgraph 验证过程["🟢 云端验签"] V1["从请求Header<br/>提取所有参数"] V1 --> V2["用keyId查到对应secretKey"] V2 --> V3["同样方法<br/>重新计算sign"] V3 --> V4{"sign == 请求sign?"} V4 -->|"是"| V5["验签通过"] V4 -->|"否"| V6["拒绝请求"] V3 -.->|"检查et时间戳"| V7{"当前时间 < et?"} V7 -->|"否"| V8["请求已过期<br/>防重放攻击"] end style S1 fill:#E3F2FD,stroke:#1976D2 style S2 fill:#FFF8E1,stroke:#F57C00 style V4 fill:#FFF8E1,stroke:#F57C00 style V5 fill:#E8F5E9,stroke:#388E3C style V6 fill:#FFEBEE,stroke:#D32F2F style V8 fill:#FFEBEE,stroke:#D32F2F

防key泄露的最佳实践:

策略 说明
key留在本地 secretKey只存设备固件/安全芯片,从不联网传输
签名用HMAC不用MD5 MD5已被破解,HMAC-SHA256是当前主流
时间戳防重放 请求带et过期时间,攻击者截获重发会被拒绝
Token短期有效 Token过期后必须重新申请,即使泄露影响有限
keyId定位而非传输key 请求只带keyId(无秘密),服务器用keyId查key
HTTPS传输 防止明文被截获(即便有签名,HTTPS仍是第一道防线)

四、总结

4.1 协议选择一句话

  • 海量设备上报 → MQTT(发布-订阅,省流量)
  • 实时语音控制 → WebSocket(双向长连接,低延迟)
  • 偶尔下发指令 → HTTPS(请求-响应,可靠加密)

4.2 安全认证一句话

  • HMAC-SHA256代替MD5:key不联网,签名走网络
  • 时间戳防重放:请求带过期时间,截获重发无效
  • 短期Token:secret换Token,泄露影响可控

参考来源

版权声明

作者linuxROS
协议本作品采用 CC BY-NC-SA 4.0 许可协议:署名-非商业性使用-相同方式共享
关注欢迎关注微信公众号 linuxROS,获取更多机器人 / 嵌入式 / Linux 干货
返回首页