我一贯推荐用户使用SSL/TLS这种标准方式来实施设备的服务器接口。当然我也清楚许多嵌入式设备采用SSL依然是有困难。困难来自以下几点:
- 嵌入式设备多采用嵌入式C/C++编程;
- 如果采用标准库,耗费RAM/ROM和计算时间;
- 如果没有使用标准库,自行开发验证安全算法耗费太多、时间。
- 即使SSL/TLS,不同Cloud供应商和证书供应商的安全套件不尽相同。
- RSA/ECC等非对称算法在某些阶段过于耗费时间。
- 互联网常见的Base64/ASCII传输方式,在嵌入式领域比较耗费资源。
- TLS证书的存储。
所以,根据安全设计原则来提供一个私有设备接口规范,是非常必要的。这里,还需要区分TCP长连接、短连接和UDP方式。
TCP长连接
如果设备使用WiFi/以太网/SocketCAN等方式连接到服务器上,则TCP长连接很适合。在Linux中,TCP称之为Stream,这一点在长连接上会造成信息在接收端所特有的沾包、半包现象。所以承载在TCP长连接之上的应用层协议,必须设计合理地帧结构来隔断、截取完整的信息。
如果TCP安全加密后,TLS其实是AES这种block加密方式,所以TCP长连接 Stream 中位数不足的可以采用padding方式,接收端部分地解决了此类问题。但是由于AES中IV的存在,需要增设一个问答方式来不断地重置IV。
TCP短连接
一些无线传感器网络如BLE/WiFi网关、Sub-1GHz WSN网关、LoRa网关,蜂窝数据等,采用短连接也很适合。TCP短连接一般没有沾包现象,典型的HTTP就是使用ASCII字符串以及回车来实现各个字段的划分的。
针对TCP短连接,如果每次重新连接,走密钥交换流程太费时间,往往在后续TCP连接中继续使用AES Session Key,同时应用层中使用Token + cookie等实现。
UDP报文
某些设备如NB-IoT天生的传输方式就是UDP方式。TCP/UDP的区别在于UDP是不保证信息一定送达,先后次序和重复发送的。也就是说UDP接收端会出现报文丢失、报文重复、次序颠倒等现象。而TCP接收端则不会出现此类现象。
虽然UDP有DTLS,但是我目前还没有研究透彻。
设备端的简化
一般常见的TLS安全套件由以下几个部分组成:
- key exchange algorithm (RSA/DH/ECDH/SRP/PSK)
- authentication (RSA/ECDSA/DSA)
- bulk encryption algorithm (DES/3DES/AES)
- message authentication code (MAC)
典型套件有:
- TLS_RSA_WITH_3DES_EDE_CBC_SHA,其中3DES_EDE_CBC是一个加密算法
- TLS_PSK_WITH_AES_128_CCM_8,IoT设备常用安全套件
- TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,IoT设备常用安全套件
假设设备采用长连接服务器,而且设备可以通过预先分配AES初始密码的(PSK, Pre-shared key)方式下发到设备和服务器中,那么安全算法中的Key Agreement已经完成了。所以剩下的就是产生Session Key启动AES加密,然后在AES加密通道中完成HMAC签名,实现双向认证即可。
所以,我和同事无意中设计的安全套件是:
TLS_PSK_WITH_AES_128_CCM_SHA
虽然它的Handshake是与TLS有些差异的。
在开发过程中,针对SHA1/SHA256的C/C++/Python源码了解了以下,发现SHA仅仅是散列算法,而HMAC-SHA才是签名算法,需要使用密钥来签名。虽然HMAC底层也是调用SHA散列算法的。这里有三个网站可以验证这些算法的正确性:
- http://www.sha1-online.com/
- https://www.freeformatter.com/hmac-generator.html
- https://quickhash.com/
应用层协议
由于是TCP长连接,带AES128块加密,所以信息的截取问题不大。但是许多嵌入式开发的资深工程师会尝试将串口协议照搬使用来实现预定义的二进制协议。但是这是在为服务器端工程师埋坑。
虽然在工程上马最初,双方使用ctype/struct等可以很简单地解决这个问题。但无论何种领域的工程师,都知道需求更改是肯定会发生的。而预先定义二进制协议,会在后续协议升级维护阶段造成很大困扰,甚至无法维护。
当一个端口面临多个版本的二进制协议,服务器端工程师心里绝对是崩溃的。所以补救措施:
- 增设VERSION字段,一旦发现版本差异,马上提示OTA,并断开连接。
- 采用更加通用的带语义解释的应用协议。
至于采用何种协议,需要双方讨论。可以使用:
- CSV;
- JSON;
- msgpack;
- 某种二进制JSON。
如果工程师一定要采用自己的二进制协议,那么服务器端团队应该提供某种透传协议工具,比如JSON schema实现二进制与JSON的互相转换,让设备端工程师和应用端工程师直接对接,而规避这种麻烦事情。
网友评论