[关闭]
@ironzhang 2017-01-05T07:31:42.000000Z 字数 3294 阅读 290

MQTT安全方案

工作


  1. |FixHeader|OptHeader|Payload|

协议设计

  1. // 协议命令
  2. const (
  3. TransportCmd = byte(0) // 传输命令
  4. HandShake1Cmd = byte(1) // 一次握手
  5. HandShake2Cmd = byte(2) // 二次握手
  6. HandShake3Cmd = byte(3) // 三次握手
  7. LanTransportCmd = byte(4) // 局域网传输命令
  8. )
  9. // 加密算法枚举定义
  10. const (
  11. None = 0 // 不加密
  12. RSA = 1 // RSA加密
  13. AES = 2 // AES加密
  14. )
  15. // FixHeader 固定头部
  16. type FixHeader struct {
  17. Version uint8 // 协议版本
  18. Cmd uint8 // 协议命令
  19. PayloadLen uint32 // Uvarint, 有效负载长度
  20. }
  21. // HandShake1Header 一次握手协议可选头部
  22. type HandShake1Header struct {
  23. Enctype uint8 // 身份认证加密方式
  24. Identifier string // 身份, 格式: Device/ID/MajorDomainID/SubDomainID/DeviceID 或 Device/Name/MajorDomainName/SubDomainName/DeviceID. 编码: 2字节length + content
  25. }
  26. // LanTransportHeader 局域网传输协议可选头部
  27. type LanTransportHeader struct {
  28. Enctype uint8 // Payload加密方式
  29. }
  30. // Packet 报文
  31. type Packet struct {
  32. FixHeader // 固定头部
  33. HandShake1Header // HandShake1可选头部
  34. LanTransportHeader // LanTransport可选头部
  35. Payload []byte // 有效负载
  36. }
  37. // HandShake1Msg 一次握手消息
  38. type HandShake1Msg struct {
  39. Enctype uint8 // 传输报文中的数据加密方式
  40. RandStr1 [32]byte // 随机值1
  41. }
  42. // HandShake2Msg 二次握手消息
  43. type HandShake2Msg struct {
  44. Token [32]byte // 加密Token, 用于加密传输报文中的传输数据
  45. RandStr1 [32]byte // 随机值1
  46. RandStr2 [32]byte // 随机值2
  47. }
  48. // HandShake3Msg 三次握手消息
  49. type HandShake3Msg struct {
  50. RandStr2 [32]byte // 随机值2
  51. }

除了固定头部和可选头部,其余协议负载可能需要加密。

三次握手

以RSA加密为例

Created with Raphaël 2.1.2clientclientmqtt_brokermqtt_brokerHandShake1.RandStr1 = 随机字符串payload = RSA加密(云端公钥, HandShake1)HandShake1 := RSA解密(云端私钥, payload)HandShake2.Token = 生成新tokenHandShake2.RandStr1 = HandShake1.RandStr1HandShake2.RandStr2 = 随机字符串payload = RSA加密(设备端公钥, HandShake2)HandShake2 = RSA解密(设备端私钥, payload)比较HandShake2.RandStr1与HandShake1.RandStr1,以确认云端身份HandShake3.RandStr2 = HandShake2.RandStr2payload = HandShake3比较HandShake3.RandStr2与HandShake2.RandStr2,以确认设备端身份,若确认为伪造设备,则断开连接三次握手完毕,开始以MQTT协议通信。如果HandShake1.Encrypt为true,则MQTT协议都以Token加密,否则不加密。

瞬断重连

之前提出的瞬断重连不再重新握手的方案都存在安全漏洞,故还是要求瞬断之后都要重新进行三次握手。

加密方案

传输层加密类似tls的方式,以Transfer报文将MQTT协议包装起来。

应用层加密只对PUBLISH报文的payload做加密

/ 传输层加密 应用层加密
加密报文 对所有MQTT报文加密 只对PUBLISH报文的payload加密
报文大小 加密会导致报文变大,特别是心跳包 只有PUBLISH报文的payload会大一点
安全风险 如果MQTT的CONNECT等报文中包含敏感信息,则存在泄露风险

新的协议设计

  1. |Header|Body|
  1. |Magic|Version|Cmd|
  1. |Cmd|ErrorNo|
  1. |Enctype|Identifier|PayloadLen|Payload|
  1. |RandStr1|PayloadLen|Payload|
  1. |RandStr2|
  1. |PayloadLen|Payload|

协议详细描述

  1. // 协议命令
  2. const (
  3. ErrorCmd = byte(0) // 错误命令
  4. HandShake1Cmd = byte(1) // 一次握手
  5. HandShake2Cmd = byte(2) // 二次握手
  6. HandShake3Cmd = byte(3) // 三次握手
  7. TransportCmd = byte(4) // 传输命令
  8. )
  9. // 加密算法枚举定义
  10. const (
  11. None = 0 // 不加密
  12. RSA = 1 // RSA加密
  13. AES = 2 // AES加密
  14. )
  15. // Packet 报文
  16. type Packet struct {
  17. Header // 固定头部
  18. Error // 错误报文
  19. HandShake1 // 一次握手报文
  20. HandShake2 // 二次握手报文
  21. HandShake3 // 三次握手报文
  22. Transport // 传输报文
  23. }
  24. // Header 头部
  25. type Header struct {
  26. Magic [2]byte // magic
  27. Version uint8 // 协议版本
  28. Cmd uint8 // 协议命令
  29. }
  30. // Error 错误报文
  31. type Error struct {
  32. Cmd uint8 // 引起错误的协议命令
  33. ErrorNo uint8 // 错误码
  34. }
  35. // HandShake1 一次握手报文
  36. type HandShake1 struct {
  37. Enctype uint8 // 身份认证加密方式
  38. Identifier string // 身份, 格式: Device/ID/MajorDomainID/SubDomainID/DeviceID
  39. PayloadLen uint32 // Uvarint, payload长度
  40. Payload []byte // 有效负载
  41. }
  42. // HandShake1Payload 一次握手报文Payload中的数据格式
  43. type HandShake1Payload struct {
  44. Enctype uint8 // 传输报文中的数据加密方式,只能是对称加密算法或不加密
  45. RandStr1 [32]byte // 随机值1
  46. }
  47. // HandShake2 二次握手报文
  48. type HandShake2 struct {
  49. RandStr1 [32]byte // 随机值1
  50. PayloadLen uint32 // Uvarint, payload长度
  51. Payload []byte // 有效负载
  52. }
  53. // HandShake2Payload 二次握手报文Payload中的数据格式
  54. type HandShake2Payload struct {
  55. Token [32]byte // 加密Token, 用于加密传输报文中的传输数据
  56. RandStr2 [32]byte // 随机值2
  57. }
  58. // HandShake3 三次握手
  59. type HandShake3 struct {
  60. RandStr2 [32]byte // 随机值2
  61. }
  62. // Transport 传输报文
  63. type Transport struct {
  64. PayloadLen uint32 // Uvarint, payload长度
  65. Payload []byte // 有效负载
  66. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注