遗憾的是,上述混合加密的方式仍然还是有漏洞的。攻击者(中间人)的确无法得到浏览器生成的对称密钥 X,这个密钥本身被公钥 A1 加密,只有使用服务器拥有的私钥 A2 才能解密。但是!攻击者完全不需要拿到服务器私有的私钥 A2 就能劫持信息。举个例子:
- 某网站服务器拥有一组用于公开密钥加密的非对称密钥:公钥 A1、私钥 A2
- 浏览器向网站服务器请求,服务器把公钥 A1 明文给传输浏览器
- 攻击者劫持到公钥 A1,保存下来,把数据包中的公钥 A1 替换成自己伪造的公钥 B1(它当然也拥有公钥 B1 对应的私钥 B2)
- 浏览器随机生成一个用于对称加密的密钥 X,用攻击者的公钥 B1(服务器此时不知道自己的公钥被替换了)加密后传给服务器
- 攻击者劫持后用自己的私钥 B2 解密就得到了密钥 X。然后再用服务器的公钥 A1 加密后传给服务器
- 服务器接收到攻击者用公钥 A1 加密的信息后,用对应的私钥 A2 解密得到密钥 X
这样在客户端浏览器和网站服务器都没有发现异常的情况下,攻击者得到了对称密钥 X。此后客户端和浏览器双方通过对称密钥 X 加密发送的任何内容,攻击者都可以轻松破解。
上述过程就是典型的中间人攻击,其根本原因是浏览器客户端无法确认自己收到的公钥是不是真正的网站服务器的。那么下一步就是解决这个问题:❓ 如何证明浏览器客户端收到的公钥一定是该网站服务器的公钥?防止服务器和客户端的身份被伪装。
其实很简单,大家想一下在现实生活中,如何证明小明说出的身份证号确实是它自己的,怎么办?看看小明的身份证就可以了。身份证是由谁颁发的?政府机构。那么这里政府机构就起到了公信的作用,它本身的权威可以对一个人的身份信息作出证明。
对应的,互联网中也有这么一个公信机构,数字证书认证机构 Certificate Authority, CA。所谓公信机构,就是客户端和浏览器都信赖的第三方机构。
网站服务器在使用 HTTPS 前,需要向 CA 申请颁发数字证书,数字证书里有证书持有者、证书持有者的公钥等信息。服务器把数字证书明文传输给浏览器客户端,然后浏览器从证书里取出服务器的公钥就可以了。
然而这里又有一个显而易见的问题:证书本身的传输过程中,如何防止被篡改?即如何证明证书本身的真实性? 数字证书怎么防伪呢?
③ 数字签名数字证书认证机构 CA 在判明提出申请者的身份之后,会对其申请的公开密钥做数字签名,然后将数字签名和公开密钥放入数字证书。而客户端在收到服务器发送来的数字证书后,对证书上面的数字签名进行验证,如何这个数字签名和证书上的原始公开密钥 Hash 后的结果一致,那么客户端便可明确两件事情:
- 认证服务器的公开密钥的是真实有效的数字证书认证机构
- 服务器的公开密钥是值得信赖的
OK,这么说还不太清楚,我们先来了解什么是数字签名?
数字证书认证机构 CA 把要传送的明文信息(也就是申请认证的网站服务器的公钥)通过 Hash 算法得出摘录信息 MIC(摘录技术),再用自己的私钥对 MIC 值进行加密,就得到了得到数字签名。
解释一下:认证机构一般会持有一组公钥 A1 和私钥 A2,为了确保证书的安全性,浏览器客户端通常会在内部事先植入常用认证机构的公钥 A1,认证机构在颁发数字证书的时候,会用自己的私钥 A2 对数字签名进行加密。而浏览器接收到数字证书后,先利用事先存储好的公钥 A1 解密数字签名,再对数字签名进行验证。
下面是这个过程的总结提炼,大家配合图片直观理解一下。
1)CA 颁发数字证书给网站的过程:
- CA 拥有非对称加密的私钥和公钥
- 网站申请数字证书,并发送自己的公开密钥 A
- CA 对网站的公开密钥 A 进行 Hash 得到摘录信息 MIC
- 对 MIC 值用 CA 的私钥加密,继而得到数字签名
- 将数字签名和网站的公开密钥 A 放进数字证书发放给网站
2)浏览器客户端验证网站数字证书的过程:
- 浏览器客户端接收到网站服务器发来的数字证书,得到网站的公钥 A 和数字签名 S1
- 浏览器使用事先植入的 CA 机构的公钥对 S1 进行解密,得到 S2
- 用数字证书里说明的 Hash 算法对网站的公钥 A 进行 Hash 得到 A2。
- 比较 S2 是否等于 A2,若相等则表示证书可信。于是浏览器就可以放心的取出数字证书中的网站公钥 A 进行使用