首先我们要明确一个概念就是说系统是相对安全的,我们可以通过各种手段增加复杂度但不能一定保证系统绝对安全,系统安全是一个相对的概念。
在我的工作中遇到过的一些tcp传输协议设计的比较简单,我们看一下它的结构,我想下面的协议应该是做基础数据传输都很常用的协议设计,无论是demo还是教程下面的传输协议算是最常用的传输方式。
协议1(tcp json传输)
| 数据长度 | 协议内容 |
|---|---|
| int | json/xml |
协议2(tcp pb传输)
| 数据长度 | 协议内容 |
|---|---|
| int | pb序列化 |
我们看一下它可能带来的一些问题
1、我们从协议结构来看长度是必须的那么这个int表示的长度非常大是不是说我们如果是一个非常规的数据包就会导致数据缓冲区的无限大。
2、协议内容如果不做校验可能会导致数据被篡改,也会导致数据长度和内容不匹配无法处理直到断开连接后才能释放数据缓冲区。
在设计一个用于公网的传输协议时我们要考虑的几个问题,数据加密、防篡改、防请求回放。
数据加密
数据加密的方式很多比如RSA、AES、DES 无论是对称加密还是非对称加密我们是需要对数据内容进行恢复做业务处理。
数据防篡改校验
数据校验的方式有很多种比如md5、sha1、crc8/16/32、或者md5(data+salt) 等等或者组合使用。
防请求重放处理
如果请求的数据量少可以通过对比数据库或者redis处理,如果请求量比较大则需对client id做滑动窗口来防止数据请求重放。
上面已经提到了解决问题的方法那么我们就开始基于上面的问题来设计一个tcp协议
| 请求头 | 加密方式 | 客户端序号 | 数据长度 | 数据内容 | crc校验 |
|---|---|---|---|---|---|
| 0x1A,0x1A | 1byte | int(小端对齐) | int(小端对齐) | byte[] | 2bye(crc16) |
下面我来说一下协议这样设计的原因,当然也有其它的方式来设计这只是一个模版,设计方式针对个人要求可以灵活设计。
| 字段 | 含义及描述 |
|---|---|
| 请求头 | 请求头有两个作用一个做作为协议多路复用处理比如我支持多种协议(协议1、协议2),又可以作为简单的安全处理比如我拒绝掉其它非法请求比如0x1F,0x23这类的数据包 |
| 加密方式 | 加密方式是用于客户端和服务端支持多套加解密方式,用于对不同加解密方式的区分,从而选择不同的解密算法对数据包内容进行解密,因为加密算法种类是固定的所以选择byte存储支持固定的加密算法即可。 |
| 客户端序号 | 客户端序号作用有两个,一个是对于消息确认的接收返回ack,另外一个是为了防止流量劫持重访攻击拒绝重复的请求 。 |
| 数据长度 | 对于流式协议处理来说使用固定分隔符或者提供数据长度才能正确判断数据的结束位置。 |
| 数据内容 | 通常数据内容用于存放传输的数据字节数组或者加密后的字节数组。 |
| crc校验 | 通常采用crc16对数据内容进行crc签名可以从协议头开始签名也可以只签名数据内容不做特殊限制。 |
如果我想让数据传输更安全一些怎么做呢?
我们可以参考tls协商能明白一个道理就是说在传输安全性上如果为了提高更快的处理我们会选择对称加密,那么对称加密的密钥管理安全提高了对于使用对称加密也就更安全一些。我们可以参考tls处理方式来借用其中一些处理过程来提高密钥生成,或者通过DH密钥协商的方式来提高会话密钥的安全性。
1、借助tls握手client random和server random我们来重新优化一下安全传输,我们可以使用fun(cleint random,server random) 方式通过固定的处理函数来生成密钥,无论我们采用 &、字符拼接、字符拼接+salt等等都可以让会话密钥生成具有一定的难度来确保会话密钥的随机性和破解难度。
2、通过DH算法做密钥协商,我们这样简单的理解DH加密算法,首先我们通过func(a)和func(b)生成的两个公开密钥A和B,A和B都可以在网络上传输,两端都有自己的私钥a,b 而会话密钥是通过A和B的交换再经过私钥a和b的合成(func(B,a)=func(A,b)=k)生成出一个共有密钥k的方式,我们很难拆解出a和b是如何生成的A和B也就不能拿到私有密钥a和b这就是其中的原理。