HTTPS详解
1. 介绍
HTTPS其实就是在TCP及HTTP之间加入了SSL/TLS协议。
解决了HTTP协议以下问题:
- 信息加密:交互信息无法被窃取
- 校验机制:无法篡改通信内容,篡改了无法通过校验
- 身份证书:可信的身份证明
2. TLS1.2握手过程
TLS中基本单位是记录(record),多个记录可以合并到一个TCP包中发送。
2.1 RSA TLS握手
2.1.1 RSA TLS握手过程分析
图中的一个框便是一个记录,可以看到RSA握手分为4步,时延为 2 RTT。
- 客户端发起TLS握手请求。
- 服务端公钥(TLS证书含有公钥),在握手阶段会传给客户端。
- 客户端在生成密钥后,使用服务端公钥加密再传回服务端。
- 服务器利用私钥解密,拿到相同的密钥。
最后便可以利用非对称加密协商好的对称密钥进行对称加密传输信息了。
完整握手过程如下图所示。
2.1.1.1 TLS第一次握手
客户端发送Client Hello
给服务端,并携带客户端TLS版本号/支持的密钥套件/随机数A
。
2.2.1.2 TLS第二次握手
记录一:Server Hello
服务端发送Server Hello
给客户端,并携带确认的TLS 版本号/确认的密码套件/随机数B
。
密钥套件格式 = 密钥交换算法 + 签名算法 + WITH + 对称加密算法 + 摘要算法
, 如果WITH前只有一个算法则表示密钥交换算法及签名算法都用它。
比如,这里选择的密码套件Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256,其实是:
密钥交换算法及签名算法为RSA非对称算法,对称加密算法为GCM分组的密钥长度128的AES对称算法,摘要算法为SHA256。
记录二:数字证书:Certificate
这个记录中包含数字证书,用于客户端验证服务器的身份是否可信。
记录三:Server Hello Done
表示二次握手结束。
2.2.1.3 客户端验证证书
客户端拿到证书后,需要先验证证书是否可信,才决定是否继续握手。
2.2.1.3.1 数字证书和CA机构
数字证书是一种用于在网络通信和信息安全领域中验证身份的数字文件。它通常包含了一个实体(例如个人、组织、设备等)的公钥及其相关信息,并由可信的数字证书颁发机构(CA,Certificate Authority)签名,以确保证书的真实性和可信度。
数字证书的主要组成部分包括:
-
公钥: 证书中包含了实体的公钥,用于加密和解密数据。这个公钥是与私钥一一对应的,但是私钥通常保持在证书的拥有者手中。
-
证书拥有者信息: 包括证书拥有者的名称、电子邮件地址等身份信息。
-
数字签名: 由证书颁发机构使用自己的(CA)私钥对证书的内容进行签名,以确保证书的完整性和真实性。通过验证签名,可以确保证书没有被篡改,并且确实由颁发机构签发。
-
证书认证机构(CA)的信息:用于证书链验证
2.2.1.3.2 数字证书签发和验证流程
签发流程
CA会将数字证书涉及的信息打包并摘要计算出Hash值。
用自己的私钥对Hash值进行加密,生成的值便是证书签名Certificate Signature。
最后将 Certificate Signature 添加在文件证书上,形成数字证书;
验证流程
客户端会通过一样的摘要算法对数字证书信息计算出一个Hash值A,再通过预置在系统中的CA公钥解密证书签名Certificate Signature得到Hash值B。
判断A和B是否相等便知道证书是否可信。
2.2.1.3.3 证书链
对于这种三级层级关系的证书的验证过程如下:
- 客户端收到 baidu.com 的证书后,发现这个证书的签发者不是根证书,就无法根据本地已有的根证书中的公钥去验证 baidu.com 证书是否可信。于是,客户端根据 baidu.com 证书中的签发者,找到该证书的颁发机构是 “GlobalSign Organization Validation CA - SHA256 - G2”,然后向 CA 请求该中间证书。
- 请求到证书后发现 “GlobalSign Organization Validation CA - SHA256 - G2” 证书是由 “GlobalSign Root CA” 签发的,由于 “GlobalSign Root CA” 没有再上级签发机构,说明它是根证书,也就是自签证书。应用软件会检查此证书有否已预载于根证书清单上,如果有,则可以利用根证书中的公钥去验证 “GlobalSign Organization Validation CA - SHA256 - G2” 证书,如果发现验证通过,就认为该中间证书是可信的。
- “GlobalSign Organization Validation CA - SHA256 - G2” 证书被信任后,可以使用 “GlobalSign Organization Validation CA - SHA256 - G2” 证书中的公钥去验证 baidu.com 证书的可信性,如果验证通过,就可以信任 baidu.com 证书。
证书链存在的原因:为了确保根证书的绝对安全性,将根证书隔离地越严格越好,如果根证书失守,那么整个信任链都有问题。
2.2.1.4 TLS第三次握手
客户端成功验证数字证书后,继续握手。
记录一:Client Key Exchange
客户端发送Client Key Exchange
给服务端,携带用服务器RSA 公钥加密后的新随机数(pre-master)。
记录二: Change Cipher Spec
此时,客户端和服务端双方都共享了三个随机数,分别是 Client Random、Server Random、pre-master。
客户端和服务端会使用这三个随机数生成AES_128_GCM算法的对称密钥,用于后续消息加密。
生成对称密钥后,发送Change Cipher Spec
消息告诉服务器开始使用对称密钥加密。
记录三:Encrypted Handshake Message
客户端发送Encrypted Handshake Message
给服务端,把之前所有发送的数据做个摘要,再用会话密钥(master secret)加密一下,让服务器做个验证,验证加密通信「是否可用」和「之前握手信息是否有被中途篡改过」。
2.2.1.5 TLS第四次握手
服务器给客户端发送Change Cipher Spec
和Encrypted Handshake Message
。
如果双方都验证加密和解密没问题,那么握手正式完成。
记录一: Change Cipher Spec
服务端发送给客户端,过程同TLS第三次握手。
记录二:Encrypted Handshake Message
服务端发送给客户端,过程同TLS第三次握手。
2.1.2 RSA缺陷
RSA 密钥协商算法不支持前向保密。
一旦服务端的私钥泄漏了,过去被第三方截获的所有 TLS 通讯密文都会被破解。因为可以通过私钥解密客户端发送的加密后的pre-master随机数。
2.2 ECDHE TLS握手
ECDHE算法具有前向安全性,所以被广泛使用,RSA算法则使用较少了。
2.2.1 DH 算法
ECDHE算法由DH算法演变而来,核心思想是离散对数。
2.2.1.1 离散对数
离散对数简单介绍下。公式如下。
底数G和模数P是离散对数公开的参数。x是对数,y是整数,用于加密。
知道对数x,可以直接算出整数y。但反过来,知道整数y却很难推算出对数x,特别当模数P是一个很大的质数时。
2.2.1.2 DH算法
现假设小红和小明约定使用 DH 算法来交换密钥,那么基于离散对数,小红和小明需要先确定模数和底数作为算法的参数,这两个参数是公开的,用 P 和 G 来代称。
然后小红和小明各自生成一个随机整数作为私钥,双方的私钥要各自严格保管,不能泄漏,小红的私钥用 a 代称,小明的私钥用 b 代称。
现在小红和小明双方都有了 P 和 G 以及各自的私钥,于是就可以计算出公钥:
小红的公钥记作 A,A = G ^ a ( mod P );
小明的公钥记作 B,B = G ^ b ( mod P );
A 和 B 也是公开的,因为根据离散对数的原理,从真数(A 和 B)反向计算对数 a 和 b 是非常困难的,至少在现有计算机的计算能力是无法破解的,如果量子计算机出来了,那就有可能被破解,当然如果量子计算机真的出来了,那么密钥协商算法就要做大的升级了。
双方交换各自 DH 公钥后,小红手上共有 5 个数:P、G、a、A、B,小明手上也同样共有 5 个数:P、G、b、B、A。
然后小红执行运算: B ^ a ( mod P ),其结果为 K,因为离散对数的幂运算有交换律,所以小明执行运算: A ^ b ( mod P ),得到的结果也是 K。
K 就是小红和小明之间用的对称加密密钥,可以作为会话密钥使用。
2.2.1.3 DHE算法
根据私钥生成的方式,DH 算法分为两种实现:
- static DH 算法,已废弃
- DHE 算法,当前使用
static DH 算法里有一方的私钥是静态的,也就说每次密钥协商的时候有一方的私钥都是一样的,一般是服务器方固定,即 a 不变,客户端的私钥则是随机生成的。
于是,DH 交换密钥时就只有客户端的公钥是变化,而服务端公钥是不变的,那么随着时间延长,黑客就会截获海量的密钥协商过程的数据,因为密钥协商的过程有些数据是公开的,黑客就可以依据这些数据暴力破解出服务器的私钥,然后就可以计算出会话密钥了,于是之前截获的加密数据会被破解,所以 static DH 算法不具备前向安全性。
既然固定一方的私钥有被破解的风险,那么干脆就让双方的私钥在每次密钥交换通信时,都是随机生成的、临时的,这个方式也就是 DHE 算法,E 全称是 ephemeral(临时性的)。
所以,即使有个牛逼的黑客破解了某一次通信过程的私钥,其他通信过程的私钥仍然是安全的,因为每个通信过程的私钥都是独立的
,这样就保证了「前向安全」。RSA无前向安全性的问题也类似static DH算法,因为其私钥值固定保存在服务器。
2.2.2 ECDHE算法
ECDHE 算法是在 DHE 算法的基础上利用了 ECC 椭圆曲线特性,避免了DHE算法的大量乘法计算,可以用更快点地计算出公钥及会话密钥。
小红和小明使用 ECDHE 密钥交换算法的过程:
- 双方事先确定好使用哪种椭圆曲线,和曲线上的基点 G,这两个参数都是公开的;
- 双方各自随机生成一个随机数作为私钥d,并与基点 G相乘得到公钥Q(Q = dG),此时小红的公私钥为 Q1 和 d1,小明的公私钥为 Q2 和 d2;
- 双方交换各自的公钥,最后小红计算点(x1,y1) = d1Q2,小明计算点(x2,y2) = d2Q1,由于椭圆曲线上是可以满足乘法交换和结合律,所以 d1Q2 = d1d2G = d2d1G = d2Q1 ,因此双方的 x 坐标是一样的,所以它是共享密钥,也就是会话密钥。
2.2.2 ECDHE TLS握手过程分析
2.2.2.1 TLS第一次握手
客户端发送Client Hello
给服务端,并携带客户端TLS版本号/支持的密钥套件/随机数A
。这步和RSA是一样的。
2.2.2.2 TLS第二次握手
记录一:Server Hello
服务端发送Server Hello
给客户端,并携带确认的TLS 版本号/确认的密码套件/随机数B
。
已经说过密钥套件格式 = 密钥交换算法 + 签名算法 + WITH + 对称加密算法 + 摘要算法
, 如果WITH前只有一个算法则表示密钥交换算法及签名算法都用它。
这里密码套件Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,表示:
- 密钥交换算法使用ECDHE
- 签名算法为RSA非对称算法
- 对称加密算法为GCM分组的密钥长度256的AES
- 摘要算法为SHA384
记录二:数字证书:Certificate
这个记录中包含数字证书,用于客户端验证服务器的身份是否可信。
记录三:数字证书:Certificate
这个记录是RSA算法握手没有的。
因为服务端选择了 ECDHE 密钥协商算法,所以会在发送完证书后,发送Server Key Exchange
消息。
这个过程服务器做了三件事:
- 选择了名为 x25519 的椭圆曲线,选好了椭圆曲线相当于椭圆曲线基点 G 也定好了,这些都会公开给客户端;
- 生成随机数作为服务端椭圆曲线的私钥,保留到本地;
- 根据基点 G 和私钥计算出服务端的椭圆曲线公钥,这个会公开给客户端。
记录四:Server Hello Done
表示二次握手结束。
2.2.2.3 TLS第三次握手
记录一:Client Key Exchange
客户端证书验证通过过,会进行第三次握手。
客户端会生成一个随机数作为客户端椭圆曲线的私钥,然后再根据服务端前面给的信息,生成客户端的椭圆曲线公钥,然后用Client Key Exchange
消息发给服务端。
记录二: Change Cipher Spec
至此,双方都有对方的椭圆曲线公钥、自己的椭圆曲线私钥、椭圆曲线基点 G。于是,双方都就计算出点(x,y),其中 x 坐标值双方都是一样的,前面说 ECDHE 算法时候,说 x 是会话密钥,但实际应用中,x 还不是最终的会话密钥,因为 TLS 设计者不信任客户端或服务器「伪随机数」的可靠性。
最终的会话密钥用客户端随机数 + 服务端随机数 + x(ECDHE 算法算出的共享密钥)
三个值生成的。
生成对称密钥后,发送Change Cipher Spec
消息告诉服务器开始使用对称密钥加密。
记录三:Encrypted Handshake Message
客户端发送Encrypted Handshake Message
给服务端,把之前所有发送的数据做个摘要,再用会话密钥(master secret)加密一下,让服务器做个验证,验证加密通信「是否可用」和「之前握手信息是否有被中途篡改过」。
2.2.2.4 TLS第四次握手
服务器给客户端发送Change Cipher Spec
和Encrypted Handshake Message
。
如果双方都验证加密和解密没问题,那么握手正式完成。
记录一: Change Cipher Spec
服务端发送给客户端,过程同TLS第三次握手。
记录二:Encrypted Handshake Message
服务端发送给客户端,过程同TLS第三次握手。
2.3 RSA和ECDHE握手算法对比
- RSA 密钥协商算法「不支持」前向保密,ECDHE 密钥协商算法「支持」前向保密;
- 使用了 RSA 密钥协商算法,TLS 完成四次握手后,才能进行应用数据传输,而对于 ECDHE 算法,客户端可以不用等服务端的最后一次 TLS 握手,就可以提前发出加密的 HTTP 数据,节省了一个消息的往返时间(这个是 RFC 文档规定的,具体原因文档没有说明,所以这点我也不太明白);
- 使用 ECDHE, 在 TLS 第 2 次握手中,会出现服务器端发出的「Server Key Exchange」消息,而 RSA 握手过程没有该消息;
3. TLS1.3握手过程
TLS1.3只需要1RTT便可建立连接,恢复连接只是0RTT。
可以看到TLS1.3不仅将握手过程的部分信息加密传输了,这个Application Data还可以直接开始传输真实的业务数据。
客户端也是同理,在完成握手的同时,也直接开始传输业务数据。故建立连接只需要1RTT。