混合加密通信 (通信协议加密方案)

1 前言

在网络通信过程中,为保证通信安全,往往需要对通信内容进行加密,以防止敏感信息失窃或被破解。做了加密之后,通常会再使用摘要算法对特定内容进行摘要,以防被篡改。目前最流行的加密方式就是HTTPS了,双方通过信任证书,协商通信秘钥,采用都支持的加密算法和摘要算法对数据进行加密传输,保证了安全性。目前几乎所有的Web应用都是基于HTTPS实现的,解决了互联网通信过程中的安全性问题。

但是,HTTPS不是万能的。随着物联网和5G通信的发展,它的通信开销(HTTP的短连接、繁冗的Header等)不容忽视,在“大连接、低时延”的场景下并非最优的选择。

本文分享一种适用于物联网、边缘计算等“长连接”环境下的加密通信方法,在保证安全性的同时,也会大幅降低通信损耗。

背景其实是同事遇到了刁钻的客户,(物联网通信场景)非说HTTPS不安全、性能不满足要求,需要出一个方案。

2 设计思路

参考HTTPS的处理流程:

1、信任证书

  • 客户端认证服务器
  • 服务器下发证书、认证客户端(双向认证)

2、协商并生成秘钥

在ssl握手过程中,客户端会生成一个随机数,将随机数与加密算法等信息使用证书中的公钥加密后发送给服务器,然后双方使用同样的算法各自计算生成真正的通信秘钥。

3、加密传输

后续使用这个秘钥对通信数据进行对称加密。

参考上述流程,我们需要解决问题有:

1、认证客户端身份

对于不合法的客户端,禁止其接入到核心系统。这是最基本的安全认证。

2、协商通信秘钥

每次身份验证通过之后,需要生成随机密码作为对称加密的秘钥,这样每次通信使用的都是不同的秘钥,提升通信的安全级别。

我们既要保证通信安全性,又要确保通信效率,要如何设计呢?

2.1 接口规范的设计

说明:本节内容旨在提升通信效率,跟加密通信无关

相较于HTTP协议,想要降低通信损耗,需从2个方面下手:

  • 减少连接建立次数
  • 压缩报文头

2.1.1 减少连接次数

原因也很好理解:每次连接的建立和释放都会经过3次握手和4次挥手,频繁的创建连接会大幅降低通信性能。可以通过“长连接+心跳”来解决这个问题。

但是在“海量连接”的场景下,所有的终端都做长连接也是不现实的。这时候就需要服务端有选择地关闭一些没有业务操作的连接。例如,某些终端虽然一直连接着服务器,但是在5分钟内并没有业务消息传输,那么就可以选择关闭这种连接。

即使这样,也有可能让服务器过载。这时候就需要在服务端做“分布式+注册中心”,终端设备在访问服务器之前,先到注册中心拉取中心服务器的列表,再按照既定的路由规则进行访问。

如果还不行,那么就需要根据业务场景设置“边缘节点”,将一部分(非核心的)计算功能拿到边缘节点来做、汇总计算结果,定期上报给中心服务器。这样一来,中心服务器只需与边缘节点建立连接就可以了,不再“压力山大”。

上述手段可以结合具体场景和实际情况组合使用,实现的难易程度个人理解可以排序如下:

长连接+心跳+定期清理 < 分布式+注册中心 < 边缘计算。

2.1.2 压缩报文头

HTTP可读性强,但是其中不乏冗余信息,对业务不一定都有用,需要轻量化。

最精简的方式就是使用类似于MQTT这种“数字节”的应用层协议。我们可以自定义报文头和报文体的组织方式,充分利用二进制的每一位。这么做之后会导致传输报文的可读性很差,不能直观地了解报文中每个字节(或二进制位)的含义。也正是这种“可读性差”,不容易被抓包工具破解,变相提升了通信的安全性。

但是,如果接口协议(或规范)泄露了怎么办?这时,就需要对传输的内容进行加密。

2.2 秘钥设计

2.2.1 通信秘钥

在通信时采用加密传输,就需要相应的加密算法和加密秘钥。加密算法一般使用业界标准的AES256/512,DES3,等等。

当然也可以自定义加密算法。但是这种情况下对接比较麻烦,对于想要接入的第三方并不友好

另外一个重要的参数就是加密秘钥。对称加密时双方必须使用相同的秘钥,那么客户端与服务器之间如何协商?

我们将HTTPS的处理流程进行简化:当用户登录成功之后,在服务端直接生成通信秘钥(CommKey),然后回传给客户端。这样,双方就不再需要各自计算秘钥了。

那么新问题来了:通信秘钥在回传的过程中如何保证安全性?当然也是加密传输。

在HTTPS中对传输的随机数采用的是非对称加密,这个算法比较复杂,而且性能很差。我们再将这个过程进行简化:对通信秘钥-CommKey进行加密(对称加密)传输,这样既简化了处理流程,也在一定程度上提升了处理效率。

对CommKey进行加密也需要一个秘钥,这个秘钥从哪里来?

2.2.2 登录秘钥

在实际的业务场景中,用户在使用设备时都需要输入自己的用户名、密码等信息登录设备。在前文我们提到,客户端设备在接入到服务器时,服务器会对其身份进行认证。这就需要在设计接口时保留相关的认证信息,如登录用户名、登录密码、会话token等等。这里的“登录密码”-LoginKey,就可以作为CommKey的加密秘钥。

但是,在客户端登录认证时需要传输LoginKey给服务器,也会有泄露的风险,怎么办?

2.2.3 设备秘钥

终端设备在出厂时会都会有唯一的序列号SeqNo,这个序列号是可见的。我们可以为每个设备设置唯一的秘钥-EquipmentKey,这个秘钥随在出厂时写入设备(或双方通过某种方式约定),在业务系统中与SeqNo一一映射,而且要满足以下约束:

  • EquipmentKey`不参与信息传输`,只负责对登录秘钥LoginKey进行加密
  • EquipmentKey在用户侧不可查询,对用户不可见

基于以上设计,就可以将EquipmentKey作为LoginKey的加密秘钥,这样就解决了秘钥明文传输的问题。

2.3 总结

到此,所有已知的安全隐患都解决了。重新梳理下思路,我们需要设计出“三重”秘钥:

1、设备秘钥-EquipmentKey

需要在出厂时写入设备,用于对用户登录秘钥进行对称加密。

2、登录秘钥-LoginKey

用户登录或激活设备时,随用户名一起使用;另一个功能是对通信秘钥进行加密。

3、通信秘钥-CommKey

数据传输过程中用于对称加密的秘钥,由服务端生成和生命周期维护。

后续文中如无特殊说明,则使用EquipmentKey代替设备秘钥,LoginKey代替登录秘钥,CommKey代替通信秘钥。

关于加密算法和摘要算法的协商,可以直接初始化进设备,也可以在客户端(设备)登录时指定。

2.3.1 流程说明

这里以iPhone与iCloud服务器为例,用户想从iCloud上*载下**通讯录时:

郑重声明:以下内容纯属“推测”,只为让大家更容易理解这种加密通信方式的使用场景和流程

  1. 用户需要使用AppleID和密码登录自己的账户,服务器对客户端进行认证。为保证登录密码(这里登录密码=LoginKey)的安全,在认证信息传输的过程中,就可以用此iPhone出厂时写入硬件的EquipmentKey对LoginKey进行加密。传输到iCloud服务器的信息至少包括:该iPhone的序列号Seq、登录用户名、对称加密后的LoginKey;
  2. iCloud服务器拿到这些信息之后,用设备的Seq找到此iPhone对应的EquipmentKey,使用EquipmentKey对LoginKey进行解密,然后验证并返回结果。如果认证成功,iCloud服务器会优先查找本地缓存中是否有`已生成且未过期`的CommKey,如果有则加密后返回;如果没有,就在本地生成指定位数的通信秘钥,并使用LoginKey进行对称加密,然后将认证结果和加密后的CommKey(也可以包括本次和后续的业务通信时使用的加密算法、摘要算法等信息)返回给此iPhone;
  3. 3. iPhone收到认证结果和CommKey之后,`保存CommKey`,然后发起业务请求,如同步云端的通讯录,请求内容使用CommKey加密后传输
  4. 4. iCloud服务器收到请求后使用设备Seq(或本次会话的标识,前提是在登录时生成并记录过,使用会话标识更合理一些)查询到CommKey,使用CommKey解密消息,然后解析业务请求,进行相应的业务操作。数据准备好之后,分批次不断的将该账号在云端的通讯录传输给这个iPhone,传输的内容使用CommKey加密;
  5. 5. iPhone收到消息之后,使用CommKey解密、保存通讯录
  6. 6. iPhone下一次发起连接之前,如果是“已登录”状态,则可以直接使用本地存储的CommKey发起业务请求;如果“登录已过期”,则需要重复步骤1进行鉴权

上述流程中我省略了摘要验证过程的描述,大家设计时不要忘记了。

2.3.2 补充

前文所述的秘钥,除设备秘钥外,都需要在服务端管理。

  • 由于LoginKey是属于用户的“资产”,需要开放接口让用户自行修改。但是在数据传输时这个秘钥必须使用EquipmentKey加密
  • CommKey的生命周期需要服务端来管理,如每次生成的CommKey有效期是12h。用户12h内重新登入,就可以重复使用这个密码;如果超过了12h,服务器需要通知客户端密码过期,让客户端重新登录、获取新的CommKey
  • EquipmentKey不能随意修改。在极端场景下(如出厂时设备中的EquipmentKey跟系统中的不一致,这种概率极小),这时需要将设备返厂、检测、重新写入,需要设备提供相应的接口或者工具来执行这个操作。

3 后记

本文提到的加密通信方案,既可以帮你怒怼刁钻客户,又能帮你省下正版证书的钱。如果你遇到了这种客户,或者想节约成本,又或者想提升通信效率,就可以采用这个方案。

可能有人会问:用HTTP2不行吗?也是长连接,不用实现那些复杂的秘钥交换流程,而且HTTP2是标准化的协议,更方便第三方的接入。这就需要从业务场景、安全性、团队构成、研发成本等等方面综合考虑了。

个人认为本文的方案还是具备一定优势的:

  1. 通信协议更加灵活,完全可以做到比HTTP2的开销更小;
  2. 安全级别更高,增加了“自定义协议”这道屏障,而且通信秘钥是可以按需随时更换

当然,你也可以根据业务发展需要让你的产品同时具备共性和个性,视场景启用相应的协议。