什么是HTTPS:
在之前的文章中我们知道HTTP是一种无状态协议,其具有比较好的传输效率,使用方便灵活可扩展,但是其在安全方面也存在一些问题如:
-
数据采用明文传输,虽然效率比较高,但数据也很容易被中间人监听已经获取,称为中间人攻击
-
无法保证传输数据的完整性, 虽然有像MD5这样的散列值校验但,如果MD5本身被修改的话,也是无法确保数据的完整性的
-
无法确定通信方的身份,使用HTTP通信时由于不需要去确定通信方的身份,任何人都可以发送请求,服务器都会发送响应,除非服务器对某些域名进行特别限制,这样服务器发送响应会就无法知道自己的响应是否会发送给目标客户端,可能发送给伪装的客户端
所以为了解决以上的问题我们有了HTTPS协议,该协议是基于HTTP协议实现的,其并非是应用层的一种新协议,从之前的HTTP直接与TCP通信改为HTTP的通信接口由SSL(Secure Socket Layer 安全套接层)与TLS(Transport Layer Security 安全传输协议)代替与TCP进行通信。HTTPS就是身披SSL外壳的HTTP。
那么SSL与TLS是如何保证HTTP传输的安全呢?这就需要从TLS握手开始说起了,传统的TLS握手采用的是RSA加密算法生成pre_random(先不用管是什么),所以也称为RSA版本,而现在主流使用的是TLS1.2的版本来保证传输的安全可靠,在2018年又有了TLS1.3,大大优化了TLS握手的过程,这几种我们文章中陆续都会介绍。
三种加密方法:
在了解具体握手之前我们首先需要知道比较常见的三种加密方法:
-
对称加密(共享密钥加密):就是加密与解密使用同一个密钥,但是在互联网的世界里我们无法确保密钥安全的传送到对方的手里,也就无法确保传输的可靠性。
-
非对称加密(公开密钥加密):有两把钥匙,分为公钥与私钥,发送数据前我们使用公开密钥进行加密,在对方收到消息后使用对方自己未公开的私有密钥进行解密,由于私有密钥谁也不知道,所以确保了传输数据的安全性,反过来也可以使用用私有密钥进行加密,使用公开密钥进行解密。
-
混合加密:虽然非对称加密是一种比较安全的方法,但是由于其在加密解密过程中会使用到复杂的数学运算,所以导致其传输速度较慢效率较低,所以我们在交换密钥阶段采取非对称加密方法,确保密钥安全的传输到对方手里,之后在通信阶段采用非对称加密方法进行加密,来提高传输的效率。
RSA握手过程:
-
首先我们的客户端会向服务器发送自己生成的随机数client_random,TLS版本号,以及加密套件列表(包括整个握手过程中需要用到的加密方法),加密套件列表中有多种组合加密方法来供服务器选择一种。
// 加密套件列表一般长这样 ➜ openssl ciphers -v ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD AES256-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA256 ... ... Cipher Suites(17 suites)
-
服务器会返回自己在加密套件列表中选择的加密套件,以及自己生成的随机数server_random,以及公钥证书。
-
到这里我们会发现一些问题,既然服务器会像浏览器发送这些数据,那么浏览器如何确保这些数据是目标服务器发送过来的呢,可不可能是其他的黑客伪造的服务器发送来的呢,也就是说我们无法验证发送数据的服务器的身份,所以这里我们引用了公钥证书。
-
公钥证书是浏览器向第三方数字证书认证机构CA(Certificate Authority),颁发给服务器的,具体过程是首先服务器向数字证书认证机构登录自己的公钥,数字认证机构在认证服务器的身份后会颁发公钥证书。
-
公钥证书由两部分组成,一部分是服务器的公开密钥,一部分是数字认证机构的签名,签名由认证机构的私有密钥生成
-
客户端在收到服务器发送来的公钥证书后首先会验证签名的有效性,来确保通信服务器身份的真实性,之后使用之前选择的加密套件中的方法RSA,来生成随机数pre_random,并用公钥证书里的公钥进行加密,之后发送给服务器
-
客户端是如何验证证书的有效性的呢?我们知道证书的签名是由数字认证机构采用他们的私有密钥生成的,为了确保对应的公钥可以到客户端的手里,在最开始公开密钥都植入到了各大浏览器里,在客户端收到公钥证书后使用植入在浏览器中的公开密钥进行解密从而验证证书的有效性,确保通信服务器的身份。
-
之后服务器使用自己的私有密钥对pre_random进行解密
-
这样无论是服务器还是浏览器,都会得到三个随机数**client_random,**server_random,pre_random,之后将这三个随机数以相同的算法进行混合生成最终的密钥。
-
最后客户端还需要向服务器发送一个收尾的消息表明,之后的数据传输都使用对称加密进行传输了,服务器在的收到消息后也会向客户端发送一样的收尾消息。
-
收尾消息包括两部分:一部分是Change Cipher Spec,代表之后要使用对称加密进行传输了,一部分是Finished,包括之前所有通信的摘要,来确保通信内容是完整的,服务器需要对其进行校验,校验的结果才可以代表这次的握手是否成功。
-
然后开始应用层的通信,即开始发送HTTP请求
-
需要注意的是,HTTP通信是一个双向认证的过程,无论是客户端还是服务器都要对彼此进行认证
TLS1.2握手过程:
其实讲完了RSA握手过程,再来讲TLS1.2的握手过程会简单许多,所以我们先来看这张图吧,我们还是一步一步来分析:
-
首先还是一样客户端向服务器发送自己生成的client_random,加密套件列表,与TLS版本,但是需要注意的是这里我们可以看一下某一个加密套件的具体内容:
ECDHE-ECDSA-AES256-GCM-SHA384
-
ECDHE:采用ECDHE算法生成最后的pre_random,注意我们在RSA握手中使用的是RSA算法生成的pre_random
-
AES256:256位的AES加密算法进行对称加密
-
AES:高级加密标准(Advanced Encryption Standard),是非常常见的对称加密算法,微信小程序就是使用这个算法进行对称加密的
-
AES加密函数是接收两个参数,一个是密钥,一个是明文,最后生成加密后的密文,解密也是相同的过程
-
GCM:对称加密过程中的分组模式
-
SHA384:一种哈希摘要算法,用来验证传输信息的完整性
-
服务器接收到信息后向客户端传输,server_random,选择出的加密套件,以及公钥证书不同的是,这里服务器还会传输以下东西:
-
服务器会使用私钥对server_random,client_random,还有server_params进行签名
-
之后将签名以及server_params传输给客户端( 这里的server_params先不用管,之后会说)
-
客户端在接收到签名以及server_params之后首先会验证签名的有效性,如果签名有效,会向服务器发送client_params,之后由server_params以及client_params传入ECDHE加密函数生成我们所需要的pre_random,所以server_params以及client_params就是ECDHE的两个参数,ECDHE又称为椭圆曲线离散对数
-
由于服务器也是需要验证客户端的身份的,所以在接收到client_params之后还是要将私钥加密,公钥解密的过程重新来一遍,来验证客户端的身份
-
这样客户端与服务器都集齐了三大参数,server_random,client_random,pre_random,这样就可以生成最终的密钥了
-
最后还是和RSA握手方法一样,彼此需要发送结尾消息代表从此开始对称加密通信,但是不同的是这次客户端发送给服务器结尾消息之后不需要再等待服务器发送结尾消息之后才进行HTTP通信,而是发送完结尾消息之后直接进行HTTP通信,这样提高了通信效率,节省了一个RTT(代表最后一个数据发送完到接收到数据的时间间隔)
这样我们TLS1.2通信就全部介绍完了,我们来总结一下其和RSA的几个区别:
-
服务器需要向客户端多发送私钥对server_random,client_random,还有server_params进行的签名与server_params
-
RSA在验证完证书的有效性之后便会通过RSA算法生成pre_random,之后通过公钥进行加密发送给服务器,服务器使用私钥进行解密,而TLS1.2是首先验证服务器发送过来签名的有效性,将client_params发送给服务器,之后通过ECDHE加密函数,传入client_params与server_params生成pre_random
-
两种握手方法都需要进行双向验证,TLS1.2在发送完结尾消息之后无需再等待服务器发送结尾消息,而是直接进行HTTP请求
之后在2018年又推出了TLS1.3其对TLS1.2又进行了许多的改进,我们接下来再细细来讲。
TLS1.3握手过程:
TLS1.2是一种非常安全可靠的加密验证方法,但是随着时间的流逝,人们总不会满足于现状,希望还能有更高效,更安全的加密方案,于是在2018年TLS1.3便被推出了。
强化安全:
TLS1.3废除了许多的加密套件,只留下了五组:
TLS_AES_128_GCM_SHA256
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
TLS_AES_128_GCM_SHA256
TLS_AES_128_GCM_8_SHA256
- 我们可以发现,对称加密方法只留下了AES与CHACHA20,AES(高级加密标准)是一种比较普遍的对称加密方法,微信小程序使用的便是AES(对AES算法感兴趣的同学可以看这篇文章AES 加密算法的原理详解)
- 分组方法只留下了GCM与POLY1305
- 哈希摘要算法只留下了SHA256与SHA384
在这里最重要的是TLS1.3废除了**RSA非对称加密算法,**这个算法号称世界上最重要的算法,没有其所有一切安全无从谈起,如果要对其进行强制解密需要对很多位的整数数进行因式分解,这是非常难以做到的,对RSA算法感兴趣的同学可以看这篇一文搞懂 RSA 算法,但为什么会被弃用呢可能主要有以下两点:
-
一个是通过2015年FREAK攻击发现了RSA加密方法的漏洞
-
一个是我们传统的RSA握手中,我们需要将pre_random使用公钥进行加密然后传递给服务器,然后服务器使用私钥进行解密,但是如果服务器的私钥被泄露了呢,我们就可以获得pre_random,client_random,server_random三个参数,从而获得最终的密钥了
当的服务器的密钥被窃取之后,之前的所有历史通话记录和以后的通话都会被破解,而如果使用ECDHE加密算法,我们压根不会向服务器传递pre_random,每次会话都会生成不同的密钥从而保证了**向前安全性,**这也是TLS1.3一个重要的更新。
性能提升:
接下来我们来看看握手过程的的更新,TLS1.3基本的握手过程还是和TLS1.2非常相似的,唯一的不同是TLS1.3的客户端不需要在验证完服务器证书的有效性后才向服务器发送client_params而是在第一次请求的时候便会发送,这意味着在第一次握手时发送的数据便会更多,我们可以来复习一下第一次需要发送哪些?有client_random,加密套件列表,TLS版本号,还有client_params,这样便会又节省了一个RTT,所以TLS1.3也也称为1-****RTT握手,但是除了减少RTT之外我们还可以优化其他部分。
会话复用:
- Session ID:每次使用HTTPS通话都会生成不同的密钥,这保证了传输的安全性,但同时也降低了传输的效率,所以在服务器与客户端通信后各自保存自己的会话ID与通信密钥,当下次客户端再需要与服务器通话时直接发送自己的会话ID,然后服务器根据会话ID查找对应的密钥,如果找到就使用密钥进行会话,不需要再通过握手生成新的密钥。但这样也有一定的问题,当多个客户端与服务器连接后服务器的存储负担将大大增加。
- Session Ticket:既然服务器的存储负担会加大,那么我们就将数据存储在客户端,具体就是当会话连接后服务器将会话状态进行加密,通过Session Ticket消息发送给客户端,客户端进行保存,下次如果再需要会话时,客户端将Ticket发送给服务器,服务器进行解密,验证其是否过期,如果没有过期就复用之前的会话状态。但是问题是如果加密的密钥泄露了呢,所有的会话状态就会泄露,所以我们需要按时验证其是否过期。
PSK:
0-RTT:既然之前我们优化到了1-****RTT,那么能不能优化到0呢,答案就是当客户端向服务器发送Session Ticket时直接带上应用数据,不需要等待服务器确认,这种方式称为Pre-Shared Key也就是**PSK。**但是如果通过中间人攻击窃取了PSK,然后不断的向服务器发送,这不就使服务器受攻击了嘛。。。。。
总结一下就是TLS1.3相比于TLS1.2有以下几方面改变:
-
废弃掉了一些加密算法,这里面主要的有RSA非对称加密算法,提高了安全性
-
优化了握手过程使达到了1-RTT
-
采用会话复用提升性能,减少生成密钥的实际,这其中有Session ID,Session Ticket
-
使用PSK将会话优化到了0-RTT连接
引用参考:掘金,神三元《HTTP灵魂之问,巩固你的 HTTP 知识体系》
掘金,洛羽Keith《TLS 详解握手流程》
日本,上野《图解HTTP》