之前看了一些网上关于 https 的文章,感觉都讲的不够完善,整篇看下来还是觉得有几个疑问点,最近学习了极客时间《透视 HTTP 协议》,稍微能摸清楚 https 的工作,写一写加强印象。
什么是安全
通常认为,通信过程具备了以下 4 个特性,可以认为安全:机密性,完整性,身份认证,不可否认。
- 机密性
指数据保密的,只有通信的对方能知道数据的内容,数据对其他方是不可见的 - 完整性
机密性虽然保证了数据不可被窃取,但是不能防止被篡改,如果通信过程数据直接被调包或者被修改,那么也是不安全的 - 身份验证
指能确认对方的身份,保证“我”在和“你”在通信而不是“他”,没有身份验证,通信的是“他”,那么再怎么机密的数据也是白搭 - 不可否认
“我”通过只有“你”知道的事情回应“你”,那么“你”就是正确的“你”
什么是 HTTPS
HTTPS 是运行在 SSL/TLS 上的 HTTP,只要弄懂了 SSL/TSL 就弄懂了 HTTPS,而 SSL/TLS 是在 OSI 模型中处于第 5 层会话层中,目前运用最广泛的 TLS 是 v1.2 版本,最新的 v1.3 兼容了 v1.2,且强大了很多。
TLS 由记录协议,握手协议,警告协议,变更密码协议,扩展协议等几个子协议组成,综合使用了对称加密,非对称加密,身份验证等多个前沿密码学技术。
加密
对称加密
安全的第 1 个特性是机密性,那么实现机密性最常用的手段就是对数据进行“加密”,把数据通过某种形式转化为谁都看不懂的乱码,只有特定的“钥匙”的人才能解密数据。加密可以分为两大类:对称加密和非对称加密。
对称加密的加密和解密的密钥都是同一个,所以是“对称”的,只要保证了密钥只有通信双方持有,那么整个通信过程就具有了机密性。
目前最常用的对称加密算法是 AES(advanced encryption standard),安全强度高,性能也很好,所以最流行。
分组模式
对称加密还有个分组模式的概念,他可以让加密算法用固定长度的密钥加密任意长度的明文,即小秘密转化为大秘密,将明文按照一定的规则切分,然后分别对明文片段进行加密,再整合成一起。现在最常见的分组模式是 GCM/CCM/Poly1305,
非对称加密
对称加密最大的问题就是如何让通信两方都知道一个密钥,总不能为了传输这个密钥再用另一个密钥进行加密吧,那就是“鸡生蛋,蛋生鸡”的问题没完没了了。
所以非对称加密就出来了。它有两个密钥,一个是 “公钥”,一个是“私钥”,两个密钥不同,所以“不对称”,私钥必须严格保密,公钥可以公开给任何人使用。
这里有个特别的“单向性”,公钥加密的数据只可以用私钥解密,反之私钥加密的数据只可以用公钥解密,常见算法有 RSA/ECC。
RSA
在 TLS1.2 版本里最常用的非对称加密算法,由于不具有“向前安全”,所以在 1.3 版本中被弃用了。
ECC
是非对称加密算法的后起之秀,他基于“椭圆曲线离散对数”的数学难题,用特定的曲线方程和基点生成一个公钥和一个私钥。子算法 ECDHE 用于密钥交换,ECDSA 用于数字签名。
混合加密
为什么 TLS 不直接使用非对称加密呢
- 因为非对称加密和解密的过程比对称加密慢太多,导致在通信的过程当中需要非常长的时间,通信龟速,实用性为 0,RSA2048 的加解密大约是 15KB/s,而 AES128 则是 13MB/s, 相差了差不多一千倍。
- 由于公钥是公开的,那么客户端的数据被窃取修改,第三方一样可以用公钥加密篡改后的数据,所以要用非对称加密进行通信,客户端需要验证服务端的身份的同时,服务端也需要验证客户端的身份,这是不现实的,要海量的客户端的身份谈何容易。
所以 TLS 只是用非对称加密算法让双方获得一个对称加密算法的密钥,后续的通信使用该密钥进行。
数字签名和证书
虽然有了机密性,但是离安全还差很远
黑客虽然拿不到密钥,但是可以通过窃听收集足够多的密文,尝试修改 / 重组后发给服务器,因为没有完整性检查,服务器正常返回,黑客可以通过服务器的响应获取进一步线索,最终破解密钥。
另外,黑客也可以伪造公钥发布,如果客户端拿到了假的公钥匙,那么再怎么加密都没有用了,被黑客直接拦截,直接裸奔。。
摘要
实现 完整性 的手段主要是 摘要算法,摘要意思就是原文的总结,概括,一个原文通过一种摘要算法只有一个摘要,所以摘要可以认为是原文的“指纹”,MD5 和 SHA- 1 是之前常见的摘要算法,但是由于安全性不足,被弃用了,现在常用的是 SHA-2。
数字签名
现实生活中解决身份认证的常见的有盖章,签名。同样的,在通信中要想实现身份认证,首先得有个唯一的东西只要你拥有——那就是非对称加密中的私钥。使用私钥加密摘要,就能够实现 数字签名 ,实现了身份认证的同时也实现了 不可否认。
数字证书和 CA
综合上述,我们已经实现了安全的 4 大特性,是不是 ok 了?
不是。
这样还有 公钥的信任 ,因为谁都可以发布公钥,我们怎么证明这个公钥就是通信对方的公钥呢?
只能引入“可信的第三方”,这个第三方就是我们常说的 CA,由他来给各个公钥签名,用自身的信誉做担保,构建起公钥的信任链。
CA 对公钥的签名认证也是由一定格式的,包括序列号,用途,颁发者,有效时间,公钥等等,再打一个包再签名,形成一个 数字证书。
HTTPS 建立连接
图上的每一个直线代表的是一个记录协议,多个记录协议会在一个 tcp 包中一同送出。
ECDHE 握手过程
- 在 tcp 建立连接后,浏览器会先发一个client hello,包含由 TLS 支持的版本号,支持的密码套件,还有一个随机数client random,用于后续生成会话密钥。
- 服务端收到后,会返回一个 server hello,包含确定 TLS 版本号,选取其中一组密码套件,比如 TLS_ECHDHE_RSA_WITH_AES256_GCM_SHA384,意思是非对称加密算法选取 ECHDHE+RSA,对称加密算法 AES256,分组模式 GCM,摘要加密算法 SHA384,还有一个随机数server random,这个同样用于后续生成会话密钥。
然后,服务器发送证书,由于服务器选择的是椭圆曲线 ECHDHE 的加密算法,所以又发送来一个server key exchanges,里面是椭圆曲线的公钥server params,再加上自己的私钥签名,防止 server params 被篡改。 - 客户端拿到了服务端的响应,这时开始验证服务端发送过来的证书是否可信,开始走证书链逐级验证:
证书是被 CA 签名了的,所以此时根据该证书的颁发者,拿到颁发者的公钥,解密出摘要,再根据摘要算法对证书内容进行摘要计算,如果计算结果跟证书上的摘要一致,则验证了 完整性和不可否认 。如果该颁发者不是 1 级 CA,那么需要验证该颁发者的身份,根据上述同样的操作验证颁发者的证书,直到根级证书。如果在此过程都验证正确,那么该颁发者可信,从而该服务器的证书可信,达到 身份验证 。
验证完成后,客户端根据服务器证书上的公钥,解密出 server key exchange 的摘要,确认无误后,得到了 server params。然后客户端按照密码套件,也生成了一个椭圆曲线的公钥 (client params) 和私钥,用 client key exchange 发送 client params 给服务端。 - 现在两方都有椭圆曲线自己的私钥和对方的公钥,生成一个叫做 pre-master 的随机数,神奇的算法让双发生成的随机数是一致的,由于私钥并没有在通信中公开,所以 pre-master 也没有在通信中公开,所以这个随机数在本次通信中只要双发知道。
- 双方根据 client random , server random, pre-master 三个随机数计算得到master secret,这个就是用于后面通信的对称密钥。
-
客户端发送一个 change cipher spec 和finished。再将之前发送的所有数据做个摘要,再用密钥加密一下,让服务器验证一下。
- 这里客户端可以马上进行 https 的通信,就是抢跑,无需等待服务器的回应,因为双方都已经在之前的握手中确定可以知道主密钥了。减少 0.5 个 rtt。
- 服务器验证完成后,发送一个 change cipher spec 和finished,之后的通信就开始密文交流。
RSA 握手过程
大体流程跟上述一致,只是 pre-master 不再通过算法生成,而是客户端直接生成随机数,然后用服务器的公钥加密,通过发送一个 client key exchange 发送给服务器,那此时双方也实现了共享 3 个随机参数。