网上对一些关于对称加密、非对称加密、数字签名、数字证书等文章虽然很多,但是没有深入研究过或者看过一点的人过段时间很快就忘记了,记忆不深刻,故写下此篇文章,用最简单的话术理解https的由来和原理。
以Client 传入hello给 Server,Server 返回ok 给Client 为例(client可以理解为浏览器,server可以理解为服务端)
首先大家都知道http传输是明文的,server端和client端的通信很容易被中间人(不法分子)被窃取,所以需要对传输的内容进行加密。
那如何加密呢?
client传入hello之前,先和server约定好一个密钥,一边各有一个,client传输hello之前对hello用这个密钥进行加密后发送给server,然后server用这个密钥解密获取到hello,反过来也是一样,server用这个密钥加密ok,返回给client,client再用此密钥进行解密,这就是最简单的对称加密算法
用这个对称加密是否安全?
1.如果双方通信,用同一个密钥,且没有其他人知道,那是安全的(如果密钥被员工偷偷告诉别人,或者被人暴力窃取了,那也不安全,这不在我们考虑范围)
2.如何把密钥传递给对方,传递密钥的过程就可能被劫持,比如server生成一个密钥并传输给client,传输过程中密钥被别人劫持了怎么办?他可以用密钥解开双方传输的任何内容
3.可以考虑把密钥写死在client里面,这样就安全了,就像第一步一样,双方写死用一个密钥,因为不存在网络传输,也就不存在被劫持的可能性,但是client如果访问多个不同的server怎么办?即浏览器不仅仅需要访问百度,还会访问阿里,腾讯, 难道client把全世界所有的server的密钥都写死到本地吗?不可能的,所以说client的密钥都是请求服务端返回给它的,但是一旦出现网络请求,就可能会被劫持,就不安全
4.如果client不是浏览器,是app的话,是否可以写死到app里面,app访问自己的服务,其实也是不可以,原因很简单,反编译app的代码就可以拿到密钥了
综上所述,对称加密也不能解决问题
出现了一种非对称加密的技术,一把私钥,一把公钥,私钥加密后的内容只能用公钥解密,反之公钥加密的内容只能私钥解密,那我们用这个技术解决上述问题
1.下面Server简称为S,Client简称为C,其中S有一把公钥和一把私钥,首先C请求S,想要获取公钥,S返回公钥给C,C用S给的公钥加密hello传给S,S用私钥解密获取到hello,然后用私钥加密ok再返回给C,乍一看好像没问题,但其实有两个问题,问题一是任何人都可以获取公钥,那么代表任何人都可以拦截S返回给C的内容,然后用S的公钥解密,只不过无法知道C传给S的内容,以为没有私钥,无法解密;问题二更严重,如果中间人拦截C请求S获取公钥这个接口,自己去请求S获取到公钥,并且返回给C一个假的公钥(可以理解为中间人自己伪造的公钥,当然也有对应的私钥),然后每次C和S通信都被中间人拦截了,中间人可以对C和S乱发信息,太不安全了,问题一最多是S返回的信息被人看到而已,而问题二是可以篡改数据给双方
2.所以这个方案还是不安全的,这时候对这个方案改良了下,既然只有一对公私钥不安全,那就两对,S有一把公钥(S公钥)和一把私钥(S私钥),C也有一把公钥(C公钥)和一把私钥(C私钥), 首先C请求S,想要获取公钥,S返回S公钥给C,C用S公钥加密自己的C公钥,再给S,这时候S用自己的S私钥解密,获取到C的C公钥,这时候双方各自持有对方的公钥,就可以用对方的公私钥加解密相互通信啦,咋一看没毛病,但是这时候中间人又出现了,中间人可以获取拦截C请求S获取公钥的接口,和上一步骤的问题二一摸一样,也就是说,C无法知道这个S公钥是真正的公钥,还是假的公钥
我们可以从现实生活举例,证明一个人真假,可以通过身份证来辨别,但是身份证都可能造假,所以必须通过一个公信机构来证明,就是政府,因为身份证是政府法的,政府可以辨别这个身份证的真假,那程序世界是否也有这个公信机构,并且给S发一个“身份证”,答案是有的,就是CA机构
1.C请求S获取公钥,S不会立马返回给C公钥,而是S去向CA机构购买一个证书(公司名/域名/过期时间/hash算法等),然后把自己的公钥也放到这个证书里面,那这个包含证书信息和公钥的东西就是数字证书,S把数字证书返回给C,那数字证书在传递的过程如何保证不被篡改,这时候出现一个技术叫做数字签名
数字签名算法:CA机构有一对公私钥,CA机构先用hash算法对证书内的明文hash,然后用私钥对这个hash值进行加密(至于为啥需要hash,你可以理解明文太长,直接加密这一系列明文性能不好,另外在浏览器解密的时候也可以重新hash明文进行对比,看看值是否一样来判断真伪)
2.S把经过数字签名后的数字证书返回给C,C拿到数字证书之后,先用CA机构的公钥(这个浏览器或系统自带的,下文会相信描述)解密,获取到明文,S的公钥,hash值H1和此证书的hash算法,然后用这个hash算法hash明文后的hash值H2,判断H1 是否等于H2,如果等于,代表明文没有被篡改,是真的证书
3.C获取到S的公钥,内部生产一个对称密钥,用S的公钥加密这个对称密钥传给S,S用自己的私钥解密获取到这个对此密钥,这样后续双方通信就可以用对称密钥进行通信,说到着你就可以理解,https就是用一系列复杂的交互最终生成这个对称加密密钥,因为对称加密性能比非对称加密性能好
4.中间人该出场了,比如中间人获取到S返回给C的证书,但是他获取到也没用,因他没有CA机构的私钥,所以没法对证书的内容进行篡改并重新加密,如果用自己的私钥加密了,C用CA机构的公钥也解密不了,代表证书被篡改了,不能用;那如果中间人自己也向S获取证书,然后拦截C向S的请求,返回自己的证书给C呢?这样C用CA机构的公钥也可以解密,但是数字签名不一样,因为明文中肯定有服务器的域名等相关信息是可以看到的,用解密后的hash算法对这个明文重新计算,得到的值和解密后的hash值一比对就知道真假了
关于CA机构的公钥怎么跑到了客户端的机器中呢?世界上这么多机器,其实浏览器和操作系统都会维护一个权威的第三方机构列表(包括它们的公钥),因为客户端接收到的证书中会写有颁发机构,客户端就根据这个颁发机构的值在本地找相应的公钥,那如果浏览器和操作系统这道防线被破了,那就。。。
还有关于这个客户端生成的对称加密密钥,其实是根据3个随机数生产,请看下图:
大概逻辑重新在捋一遍:
1.客户端会发送 Client Hello 消息到服务器,以明文传输TLS 版本信息、加密套件候选列表、压缩算法候选列表等信息。另外,还会有一个客户端自己生成的随机数,在协商对称密钥的时候使用
2.服务器会返回,选择使用的协议版本、加密套件、压缩算法等,还有一个服务自己生成的随机数,用于后续的密钥协商
3.服务端紧接着还会返回服务器端的证书(通过CA机构申请下来的正式),然后说:“Server Hello Done,我这里就这些信息了
4.客户端拿到这个证书,需要通过CA机构的公钥进行解密,问题是怎么确认这个CA的公钥就是对的?
所以,CA 的公钥也需要更牛的 CA 给它签名,然后形成 CA 的证书。要想知道某个 CA 的证书是否可靠,要看 CA 的上级证书的公钥,能不能解开这个 CA 的签名。就像你不相信区公安局,可以打电话问市公安局,让市公安局确认区公安局的合法性。这样层层上去,直到全球皆知的几个著名大 CA,称为root CA,做最后的背书。通过这种层层授信背书的方式,从而保证了非对称加密模式的正常运转。
比如客户端先从自己本地信任的 CA 仓库的公钥进行解密,当然这个过程很复杂,可能会不断往上追溯 CA、CA 的CA、CA 的 CA 的 CA,反正直到一个授信的 CA,就可以了。
注:所以大部分独角兽网站都有自己的子证书+root证书,如下图美团,如果只有root证书,还是可以破解的。
5.客户端对这个证书验证成功之后,再生成一个随机数字 Pre-master,发送 Client Key Exchange,用服务端返回的证书中解密获取到的公钥加密,再发送给服务器,服务器可以通过私钥解密出来
6.到目前为止,无论是客户端还是服务器,都有了三个随机数,分别是:自己的、对方的,以及刚生成的Pre-Master 随机数。通过这三个随机数,可以在客户端和服务器各自都可以产生相同的对称密钥,如上图红色部分
7.有了这个对称密钥,客户端就可以说:“Change Cipher Spec,咱们以后都采用协商的通信密钥和加密算法进行加密通信了。”然后发送一个 Encrypted Handshake Message,将已经商定好的参数等,采用协商密钥进行加密,发送给服务器用于数据与握手验证
8.服务器也可以发送 Change Cipher Spec,说:“没问题,咱们以后都采用协商的通信密钥和加密算法进行加密通信了”,并且也发送 Encrypted Handshake Message 的消息试试。当双方握手结束之后,就可以通过对称密钥进行加密传输了
9.这个过程除了加密解密之外,其他的过程和 HTTP 是一样的,过程也非常复杂。上面的过程只包含了 HTTPS 的单向认证,也即客户端验证服务端的证书,是大部分的场景,也可以在更加严格安全要求的情况下,启用双向认证,双方互相验证证书