ssl-tls
握手流程
-
客户端发起请求,发送clirand
-
服务端发送签名证书,公钥,serrand
-
客户端校验证书合法性
- 证书签发会对内容进行hash计算签名值,然后对签名进行私钥加密,并把加密后的签名加到证书
- 客户端根据证书CA获取签发的机构的公钥,对签名解密,获取hash值
- 客户端自己对证书hash,比较hash是否相同,相同则信任^[https://www.zhihu.com/question/37370216]
因为CA的私钥是未知的,伪造证书无法生成相同hash值
-
客户端再生成secretrand,并且使用公钥加密,发送到服务端
-
服务端进行私钥解密得到secretrand,将三个随机数连接并进行hash算法,得到值作为加密密钥,进行对称加密^[https://www.cnblogs.com/enoc/p/tls-handshake.html]
tls1.3
- 双方事先确定好使用哪种椭圆曲线,和曲线上的基点 G,这两个参数都是公开的;
- 双方各自随机生成一个随机数作为私钥d,并与基点 G相乘得到公钥Q(Q = dG),此时小红的公私钥为 Q1 和 d1,小明的公私钥为 Q2 和 d2;
- 双方交换各自的公钥,最后小红计算点(x1,y1) = d1Q2,小明计算点(x2,y2) = d2Q1,由于椭圆曲线上是可以满足乘法交换和结合律,所以 d1Q2 = d1d2G = d2d1G = d2Q1 ,因此双方的 x 坐标是一样的,所以它是共享密钥,也就是会话密钥。
具体流程
- 客户端发起请求,发送clirand
- 服务端发送证书,服务端serrand,告诉客户端选择哪一个椭圆曲线,相当于定好椭圆曲线基点 G,到现在都是明文状态
- 生成随机数作为服务端椭圆曲线的私钥,保留到本地;
- 根据基点 G 和私钥计算出服务端的椭圆曲线公钥,这个会公开给客户端。
- 检验证书合法性,这一步步骤和上文类似
- 客户端会生成一个随机数作为客户端椭圆曲线的私钥,然后再根据服务端前面给的信息,生成客户端的椭圆曲线公钥发给服务端
- 双方都有对方的椭圆曲线公钥、自己的椭圆曲线私钥、椭圆曲线基点 G。于是,双方都就计算出点(x,y),其中 x 坐标值双方都是一样的,x就是第三个随机数最后使用x+clirand+serrand生成对称密钥
每次握手的公私钥都不一样,使得具有前向安全性
QA
- 服务端随机数的作用
- 避免重放攻击
- 攻击路由直接截取https加密后的报文,等下一次再有相同https连接时候,重新发送
- 通过serrand,使得握手得到的secretrand,不同,避免重放
- 避免重放攻击
- 客户端随机数作用
- 和服务端一样避免重放攻击
- 作为salt
- 为什么不用secretrand作为随机数
- 高内聚低耦合,再密钥层面统一方法,和DH加密兼容,模块化
- 如何进攻https协议
tira-im加密
- client生成随机数clirand,和登陆的sessionid,用公钥加密(或者通过jwt使用id作为第三个随机数)上传到服务端
- server得到后解密,先通过session验证客户端身份,生成随机数serrand,并用私钥匙加密serrand,发送serrand和加密后内容
- client用公钥解密内容,比较是否和serrand相等,验证了服务端的身份,并且双方都使用md5(clirand+serrand+sessionid)作为aes对称加密的密钥
区别联系
- 因为app内置公钥,无需发送公钥的步骤
- 通过sessionid代替第三个随机数,使得简化了流程
- TSL需要cli发,ser发,cli发,才能协商成功,im只需要cli发,ser发就可以,简化步骤
- 这个可以复用im的一个req和一个ack的通道
缺点
- 不支持前向加密,所以一旦服务端的私钥泄漏了,过去被第三方截获的所有 TLS 通讯密文都会被破解
- 没有防止重放,RSA算法还是有点过时
- RSA性能不如ECDH,而且要达到非常安全密钥长度很大
- 产生密钥很费事,遭到素数产生技术的束缚,因此难以做到一次一密
微信
访问控制
MMTLS
- 这部分底层原理还是TLS1.3,但是加入时间戳的概念防止重放
- 加解密的过程和加密系统 > MMLAS类似,只是更加复杂
通用加解密
- 用于数据库的mac生成和校验,防止直接对数据库的篡改,以及其他需要业务侧的加解密的服务提供
其他方案
- 直接在代码或者配置文件里面写死密钥(弊端:内部人员可轻易从代码、配置中获得密钥)
- 在共享内存中明文存储密钥(弊端:attach内存,轻易获得)
- 密钥保存在指定运维同事才有权限登录的服务器上,业务进程定期RPC获取密钥缓存至本地(弊端:gdb业务进程轻易获取)
- 在指定运维同事才有权限登录的服务器上保存密钥及部署统一加解密服务,业务每次加解密操作都需要走RPC调用(弊端:RPC存在耗时高、网络波动、网络分区等风险,影响业务的可用性)
密钥svr和agent流程
- 通讯链路使用ECDH协商出来的对称密钥进行AES加密
业务和agent流程
- 通过SCM_RIGHTS,将自己的pid以及eventfda发送给agent
- agent通过pid以及eventfda拿到fd,自己也建立eventfdb,发送给业务
- 业务需要加解密的时候,将需要加解密的content写入共享内存,然后通过eventfda发送共享内存的地址给agent
- agent加解密之后,通过eventfdb将共享内存的地址发送给业务方
容灾
双agent
- 部署两个agent,分为开发Develop版、稳定Stable版。
密钥文件
用户大规模故障导致agent挂了
- SafeKeyBakSvr定期从SafeKeyStoreSvr拉取每个业务对应需要的密钥,按照每个业务一个密钥文件存储起来
- 当出灾时,SafeKeyAgent已无法正常加解密。运维执行事先已备好的shell脚本,将对应业务的密钥文件推送到出灾机器
- 出灾机器的BusinessProcess检测到本地密钥文件存在时,启动容灾机制,直接从密钥文件取得密钥,绕过SafeKeyAgent直接加解密数据
- 待故障恢复后,SafeKeyAgent把容灾的密钥文件删除。BusinessProcess恢复使用SafeKeyAgent进行加解密
- 为了降低出灾时BusinessProcess直接持有密钥所带来的可能泄露风险,待故障恢复后,更新对应密钥的版本,后续加密请求使用最新版本密钥。
临时加解密
- 针对SafeKeyAgent已拉取到密钥,而因为服务过载等原因导致处理超时严重的情况,我们通过后台下发容灾指令,SafeKeyAgent收到容灾指令以后,把密钥写入到共享内存,临时由BusinessProcess从共享内存拿到密钥,直接进行本地加解密,从而快速减轻SafeKeyAgent的服务压力。待故障恢复后,SafeKeyAgent把共享内存的密钥清除,恢复SafeKeyAgent加解密。
模块认证
MMLAS
流程
- client第一次连接的时候使用证书链的认证方式,Client的证书经过CA签名,Server用CA的公钥验证Client证书,再用Client证书中的公钥认证Client用私钥的签名。验证签名通过后看时间戳是否合法,合法则Server得到可信的Client身份了。实际上逻辑还是client调用的时候把证书和公钥都发过去,服务器拿着公钥和证书验证client身份,以及解出随机数,服务端生成服务端随机数之后通过公钥加密,client使用私钥解密的到随机数,并且两者使用对称加密.这种认证方式需要Client一次签名和Server两次验签,在短链接高QPS的场景下肯定是不可接受的。所以在这种认证过程中会协商出对称密钥TicketAuthKey,为后续基于Ticket的认证做准备。
- Server会有一套只有自己知道的密钥称TicketKey,Server用TicketKey把协商出来的对称密钥TicketAuthKey(MD5(cli_ran,svr_cli))和一些信息进行加密,生成Ticket,并把Ticket返回给Client。Client把Ticket和TicketAuthKey保存起来。这里svr不保存ticket以及TicketAuthKey
- 下次Client再向Server发起认证时,只需要用TicketAuthKey对当前时间戳加密,把加密时间戳和Ticket一起给到Server。Server用TicketKey解密Ticket得到TicketAuthKey,再用TicketAuthKey解密得到时间戳,如果时间戳在合理范围内则认证通过(这里是为了防止重放攻击)
- TicketKey并不是每个Server唯一,而是每个模块唯一,一个模块的所有Server共用一套TicketKey。这样Client只要向其中一台Server用证书/私钥认证通过获得Ticket,后续就可以用Ticket往模块中的任意Server发起认证。这种TicketKey只需要对称密钥解密,性能高,确保后台海量服务的高性能。
两者区别
- ssl-tls和tira-im本质上都是tls1.2的产物,底层非对称加密算法都是RSA,现在RSA已经被证明不安全,微信这一套用的是tls1.3使用ECDH和PSK更加先进和安全
- 微信使用时间戳实现防重放效果
端到端加密
- 底层原理就是依赖公钥私钥的不对称加密的性质
流程
- 用户生成密钥,在本地生成非对称RSA密钥
- 将公钥发送到服务器中
- 别人发消息时候先获取服务器中用户的公钥
- 将消息用公钥进行加密
- 用户获得消息后使用私钥解密 ^[https://juejin.cn/post/7330440381278486565]
QA
换主机更换密钥
- 登录之后判断用户密钥是否值当前机器的密钥,如果不是,那么替换密钥,这一步需要登录状态
- 这里可能出现问题是如果用户手机丢了,在他下一次换密钥之间的所有消息都无法解密了
多主机如何同步密钥
- 手机端为主,电脑端登录的时候可以通过手机生成随机6位的数字作为AES对称加密密钥
- 然后AES加密私钥上传到服务器
- 用户在电脑端输入这六位数字,拉取加密后的数据并解密,完成密钥同步