HTTPS
1. HTTP 与 HTTPS 区别
2. HTTPS 解决了 HTTP 的哪些问题?
3. HTTPS 是如何解决 HTTP 的三个风险的?
4. HTTPS 是如何建立连接的?其间交互了什么?
- TLS 握手过程简述
- RSA 算法握手详解
5. 客户端验证证书
- 数字证书和 CA 机构
- 数字证书签发和验证流程
- 证书链
6. ECDHE 算法
- DH 算法
- DHE 算法
- ECDHE 算法
- RSA 和 ECDHE 握手过程的区别
- ECDHE 握手过程详解
1. HTTP 与 HTTPS 区别
-
HTTP 是超文本传输协议,信息是明文传输,存在安全风险的问题;HTTPS 则解决 HTTP 不安全的缺陷,在 TCP 和 HTTP 层之间加入了 SSL/TLS 安全协议,使得报文能够加密传输。
-
HTTP 连接建立相对简单, TCP 三次握手之后便可进行 HTTP 的报文传输;而 HTTPS 在 TCP 三次握手之后,还需进行 SSL/TLS 的握手过程,才可进入加密报文传输。
-
HTTP 的端口号是 80;HTTPS 的端口号是 443。
-
HTTPS 协议需要向 CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的。
2. HTTPS 解决了 HTTP 的哪些问题?
HTTP 由于是明文传输,所以安全上存在以下三个风险:
- 窃听风险,比如通信链路上可以获取通信内容。
- 篡改风险,比如强制入垃圾广告,视觉污染。
- 冒充风险,比如冒充淘宝网站。
HTTPS 在 HTTP 与 TCP 层之间加入了 SSL/TLS 协议。可以很好地解决了上述的风险:
- 信息加密:交互信息无法被窃取。
- 校验机制:无法篡改通信内容,篡改了就不能正常显示。
- 身份证书:证明淘宝是真的淘宝网。
可见,只要自身不做「恶」,SSL/TLS 协议是能保证通信是安全的。
3. HTTPS 是如何解决 HTTP 的三个风险的?
-
混合加密的方式实现信息的机密性,解决了窃听的风险。
-
摘要算法的方式来实现完整性,它能够为数据生成独一无二的「指纹」,指纹用于校验数据的完整性,解决了篡改的风险。
-
将服务器公钥放入到数字证书中,解决了冒充的风险。
1. 混合加密
混合加密的方式实现信息的机密性,解决了窃听的风险。
HTTPS 采用的是对称加密和非对称加密结合的「混合加密」方式:
- 在通信建立前采用非对称加密的方式交换「会话秘钥」,后续就不再使用非对称加密。
- 在通信过程中全部使用对称加密的「会话秘钥」的方式加密明文数据。
采用「混合加密」的方式的原因:
- 对称加密只使用一个密钥,运算速度快,但密钥必须保密,无法做到安全的密钥交换。
- 非对称加密使用两个密钥:公钥和私钥,公钥可以任意分发而私钥保密,解决了密钥交换问题,但速度慢。
2. 摘要算法
摘要算法用来实现完整性,能够为数据生成独一无二的「指纹」,用于校验数据的完整性,解决了篡改的风险。
客户端在发送明文之前会通过摘要算法算出明文的「指纹」,发送的时候把「指纹 + 明文」一同加密成密文后,发送给服务器,服务器解密后,用相同的摘要算法算出发送过来的明文,通过比较客户端携带的「指纹」和当前算出的「指纹」做比较,若「指纹」相同,说明数据是完整的。
3. 数字证书
客户端先向服务器端索要公钥,然后用公钥加密信息,服务器收到密文后,用自己的私钥解密。
这就存在些问题,如何保证公钥不被篡改和信任度?
所以这里就需要借助第三方权威机构 CA(数字证书认证机构),将服务器公钥放在数字证书(由数字证书认证机构颁发)中,只要证书是可信的,公钥就是可信的。
通过数字证书的方式保证服务器公钥的身份,解决冒充的风险。
4. HTTPS 是如何建立连接的?其间交互了什么?
TLS 1.2 握手过程简述
SSL/TLS 协议基本流程:
- 客户端向服务器索要并验证服务器的公钥。
- 双方协商生产「会话秘钥」。
- 双方采用「会话秘钥」进行加密通信。
前两步也就是 SSL/TLS 的建立过程,也就是握手阶段。
有了 TLS 协议,能保证 HTTP 通信是安全的了,那么在进行 HTTP 通信前,需要先进行 TLS 握手。TLS 的握手过程,如下图:
上图简要概述来 TLS 1.2 的握手过程,其中每一个「框」都是一个记录(record),记录是 TLS 收发数据的基本单位,类似于 TCP 里的 segment。多个记录可以组合成一个 TCP 包发送,所以通常经过「四个消息」就可以完成 TLS 握手,然后就可以在安全的通信环境里发送 HTTP 报文,实现 HTTPS 协议:
1. ClientHello
首先,由客户端向服务器发起加密通信请求,也就是 ClientHello
请求。
在这一步,客户端主要向服务器发送以下信息:
- 客户端支持的 SSL/TLS 协议版本:如 TLS 1.2 版本。
- 客户端生产的随机数(
Client Random
):后面用于生产「会话秘钥」(即数据传输时,所使用的对称加密密钥)。 - 客户端支持的密码套件列表:如 RSA 加密算法。
2. SeverHello
服务器收到客户端请求后,向客户端发出响应,也就是 SeverHello
。服务器回应的内容有如下内容:
- 确认 SSL/ TLS 协议版本:如果浏览器不支持,则关闭加密通信。
- 服务器生产的随机数(
Server Random
):后面用于生产「会话秘钥」。 - 确认的密码套件列表:如 RSA 加密算法。
- 服务器的数字证书。
3.客户端回应
客户端收到服务器的回应之后,首先通过浏览器或者操作系统中的 CA 公钥,确认服务器的数字证书的真实性。
如果证书没有问题,客户端会从数字证书中取出服务器的公钥,然后使用它加密报文,向服务器发送如下信息:
- 一个随机数(
pre-master key
):该随机数会被服务器公钥加密。(TLS 设计者不信任客户端或服务器「伪随机数」的可靠性,为了保证真正的完全随机,把三个不可靠的随机数混合起来,「随机」的程度就非常高了) - 加密通信算法改变通知:表示随后的信息都将用「会话秘钥」加密通信。
- 客户端握手结束通知:表示客户端的握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供服务端校验。
上面第一项的随机数是整个握手阶段的第三个随机数,这样服务器和客户端就同时有三个随机数,接着就用双方协商的加密算法,各自生成本次通信的「会话秘钥」。
4. 服务器的最后回应
服务器收到客户端的第三个随机数(pre-master key
)之后,通过协商的加密算法,计算出本次通信的「会话秘钥」。然后,向客户端发生最后的信息:
- 加密通信算法改变通知:表示随后的信息都将用「会话秘钥」加密通信。
- 服务器握手结束通知:表示服务器的握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供客户端校验。
至此,整个 SSL/TLS 的握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的 HTTP 协议,只不过用「会话秘钥」加密内容。
所以可以发现,HTTPS 是应用层协议,需要先完成 TCP 连接建立,然后走 TLS 握手过程后,才能建立通信安全的连接。
事实上,不同的密钥交换算法,TLS 的握手过程可能会有一些区别。
这里先简单介绍下密钥交换算法,因为考虑到性能的问题,所以双方在加密应用信息时使用的是对称加密密钥,而对称加密密钥是不能被泄漏的,为了保证对称加密密钥的安全性,故使用非对称加密的方式来保护对称加密密钥的协商,这个工作就是密钥交换算法负责的。
RSA 算法握手详解
传统的 TLS 握手基本都是使用 RSA 算法来实现密钥交换的,在将 TLS 证书部署服务端时,证书文件中包含一对公私钥,其中公钥会在 TLS 握手阶段传递给客户端,私钥则一直留在服务端,一定要确保私钥不能被窃取。
在 RSA 密钥协商算法中,客户端会生成随机密钥,并使用服务端的公钥加密后再传给服务端。根据非对称加密算法,公钥加密的消息仅能通过私钥解密,这样服务端解密后,双方就得到了相同的密钥,再用它加密应用消息。
接下来,我们就以最简单的 RSA
密钥交换算法,来看看它的 TLS 握手过程(涉及四次通信)。可见下图:
SSL/TLS 协议建立的详细流程:
TLS 第一次握手
首先,由客户端向服务器发起加密通信请求,也就是 ClientHello
请求。
在这一步,客户端主要向服务器发送以下信息:
(1)客户端支持的 SSL/TLS 协议版本,如 TLS 1.2 版本。
(2)客户端生成的随机数(Client Random
),后面用于生产会话秘钥(Master Secret)(即数据传输时,所使用的对称加密密钥)。
(3)客户端支持的密码套件列表,如 RSA 加密算法。
TLS 第二次握手
2.1 SeverHello
服务器收到客户端请求后,向客户端发出响应,也就是 SeverHello
。服务器回应的内容有如下内容:
- 确认 SSL/ TLS 协议版本,如果浏览器不支持,则关闭加密通信。
- 服务器生成的随机数(
Server Random
),后面用于生产「会话秘钥」。 - 确认的密码套件列表,如 RSA 加密算法。
2.2 Server Certificate
服务端为了证明自己的身份,会发送「Server Certificate」给客户端,这个消息里含有数字证书。
2.3 Server Hello Done
服务端发「Server Hello Done」消息,目的是告诉客户端,我已经把该给你的东西都给你了,本次打招呼完毕。
TLS 第三次握手(客户端回应)
3.1 Change Key Exchange
客户端收到服务器的回应之后,首先通过浏览器或者操作系统中的 CA 公钥,确认服务器的数字证书的真实性。
客户端就会生成一个新的随机数 (pre-master),用服务器的 RSA 公钥加密该随机数,通过「Change Key Exchange」消息传给服务端。
服务端收到后,用私钥解密,得到客户端发来的随机数 (pre-master)。至此,客户端和服务端双方都共享了三个随机数,分别是 Client Random、Server Random、pre-master。
于是,双方根据已经得到的三个随机数,生成会话密钥 (Master Secret),它是对称密钥,用于对后续的 HTTP 请求/响应的数据加解密。
3.2 Change Cipher Spec
生成完会话密钥后,然后客户端发一个「Change Cipher Spec」,告诉服务端开始使用加密方式发送消息。
3.3 Encrypted Handshake Message(Finishd)
然后,客户端再发一个「Encrypted Handshake Message(Finishd)」消息,把之前所有发送的数据做个摘要,再用会话密钥(master secret)加密一下,让服务器做个验证,验证加密通信是否可用,以及使用摘要算法验证之前的握手信息是否有被中途篡改过。
可以发现,「Change Cipher Spec」之前传输的 TLS 握手数据都是明文,之后都是对称密钥加密的密文。
TLS 第四次握手(服务端回应)
服务器也是同样的操作,发「Change Cipher Spec」和「Encrypted Handshake Message」消息,如果双方都验证加密和解密没问题,那么握手正式完成。
至此,整个 SSL/TLS 的握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的 HTTP 协议,只不过用「会话秘钥」加密内容。
5. 客户端验证证书
客户端拿到了服务端的数字证书后,要怎么校验该数字证书是真实有效的呢?
数字证书和 CA 机构
在说校验数字证书是否可信的过程前,我们先来看看数字证书是什么,一个数字证书通常包含了:
- 服务端公钥
- 持有者信息
- 证书认证机构(CA)的信息
- CA 对这份文件的数字签名及使用的算法
- 证书有效期
- 还有一些其他额外信息
那数字证书的作用,是用来认证公钥持有者的身份,以防止第三方进行冒充。说简单些,证书就是用来告诉客户端,该服务端是否是合法的,因为只有证书合法,才代表服务端身份是可信的。
我们用证书来认证公钥持有者的身份(服务端的身份),那证书又是怎么来的?又该怎么认证证书呢?
为了让服务端的公钥被大家信任,服务端的证书都是由 CA(Certificate Authority,证书认证机构)签名的,CA 就是网络世界里的公安局、公证中心,具有极高的可信度,所以由它来给各个公钥签名,信任的一方签发的证书,那必然证书也是被信任的。
之所以要签名,是因为签名的作用可以避免中间人在获取证书时对证书内容的篡改。
数字证书签发和验证流程
下图为数字证书签发和验证流程:
CA 签发证书的过程,如上图左边部分:
-
首先 CA 会把持有者的公钥、用途、颁发者、有效时间等信息打成一个包,然后对这些信息进行 Hash 计算,得到一个 Hash 值;
-
然后 CA 会使用自己的私钥将该 Hash 值加密,生成 Certificate Signature,也就是 CA 对证书做了签名;
-
最后将 Certificate Signature 添加在文件证书上,形成数字证书。
客户端校验服务端的数字证书的过程,如上图右边部分:
-
首先客户端会使用同样的 Hash 算法获取该证书的 Hash 值 H1;
-
通常浏览器和操作系统中集成了 CA 的公钥信息,浏览器收到证书后可以使用 CA 的公钥解密 Certificate Signature 内容,得到一个 Hash 值 H2 ;
-
最后比较 H1 和 H2,如果值相同,则为可信赖的证书,否则则认为证书不可信。
证书链
但事实上,证书的验证过程中还存在一个证书信任链的问题,因为我们向 CA 申请的证书一般不是根证书签发的,而是由中间证书签发的,比如百度的证书,从下图你可以看到,证书的层级有三级:
对于这种三级层级关系的证书的验证过程总得来说,由于用户信任 GlobalSign,所以由 GlobalSign 所担保的 baidu.com 可以被信任。另外由于用户信任操作系统或浏览器的软件商,所以由软件商预载了根证书的 GlobalSign 都可被信任。
这样的一层层地验证就构成了一条信任链路,整个证书信任链验证流程如下图所示:
最后一个问题,为什么需要证书链这么麻烦的流程?Root CA 为什么不直接颁发证书,而是要搞那么多中间层级呢?
这是为了确保根证书的绝对安全性,将根证书隔离地越严格越好,不然根证书如果失守了,那么整个信任链都会有问题。
6. ECDHE 密钥交换算法
RSA 算法的缺陷
使用 RSA 密钥协商算法的最大问题是不支持前向保密。因为客户端传递随机数(用于生成对称加密密钥的条件之一)给服务端时使用的是公钥加密的,服务端收到后,会用私钥解密得到随机数。所以一旦服务端的私钥泄漏了,过去被第三方截获的所有 TLS 通讯密文都会被破解。
DH 算法
为了解决这一问题,于是就有了 DH 密钥协商算法,这里简单介绍它的工作流程:
客户端和服务端各自会生成随机数,并以此作为私钥,然后根据公开的 DH 计算公式算出各自的公钥,通过 TLS 握手双方交换各自的公钥,这样双方都有自己的私钥和对方的公钥,然后双方根据各自持有的材料算出一个随机数,这个随机数的值双方都是一样的,这就可以作为后续对称加密时使用的密钥。
DH 密钥交换过程中,即使第三方截获了 TLS 握手阶段传递的公钥,在不知道的私钥的情况下,也是无法计算出密钥的,而且每一次对称加密密钥都是实时生成的,实现前向保密。
但因为 DH 算法的计算效率问题,后面出现了 ECDHE 密钥交换算法,我们现在大多数网站使用的正是 ECDHE 密钥交换算法。
DHE 算法
根据私钥生成的方式,DH 算法分为两种实现:
- static DH 算法:已被废弃
- DHE 算法:现在常用
static DH 算法里有一方的私钥是静态的,也就说每次密钥协商的时候有一方的私钥都是一样的,一般是服务器方固定,而客户端的私钥则是随机生成的。
于是,DH 交换密钥时就只有客户端的公钥是变化,而服务端公钥是不变的,那么随着时间延长,黑客就会截获海量的密钥协商过程的数据,因为密钥协商的过程有些数据是公开的,黑客就可以依据这些数据暴力破解出服务器的私钥,然后就可以计算出会话密钥了,于是之前截获的加密数据会被破解,所以 static DH 算法不具备前向安全性。
既然固定一方的私钥有被破解的风险,那么干脆就让双方的私钥在每次密钥交换通信时,都是随机生成的、临时的,这个方式也就是 DHE 算法,E 全称是 ephemeral(临时性的)。
所以,即使有个牛逼的黑客破解了某一次通信过程的私钥,其他通信过程的私钥仍然是安全的,因为每个通信过程的私钥都是没有任何关系的,都是独立的,这样就保证了「前向安全」。
ECDHE 算法
ECDHE 算法是在 DHE 算法的基础上利用了 ECC 椭圆曲线特性,可以用更少的计算量计算出公钥,以及最终的会话密钥。
这个过程中,双方的私钥都是随机、临时生成,不公开的,即使根据公开的信息(椭圆曲线、公钥、基点 G)也是很难计算出椭圆曲线上的离散对数(私钥)。
根据下图 ECDHE 密钥协商算法的 TSL 握手过程,可以看到是四次握手:
使用了 ECDHE,在 TLS 第四次握手前,客户端就已经发送了加密的 HTTP 数据,而对于 RSA 握手过程,必须要完成 TLS 四次握手,才能传输应用数据。
所以,ECDHE 相比 RSA 握手过程省去了一个消息往返的时间,这个有点「抢跑」的意思,它被称为是「TLS False Start」,跟「TCP Fast Open」有点像,都是在还没连接完全建立前,就发送了应用数据,这样便提高了传输的效率。
RSA 和 ECDHE 握手过程的区别
-
RSA 密钥协商算法「不支持」前向保密;ECDHE 密钥协商算法「支持」前向保密;
-
使用了 RSA 密钥协商算法,TLS 完成四次握手后,才能进行应用数据传输;而对于 ECDHE 算法,客户端可以不用等服务端的最后一次 TLS 握手,就可以提前发出加密的 HTTP 数据,节省了一个消息的往返时间;
-
使用 ECDHE, 在 TLS 第 2 次握手中,服务器端会发出「Server Key Exchange」消息;而 RSA 握手过程没有该消息。
ECDHE 握手过程详解
TLS 第一次握手
客户端首先会发一个「Client Hello」消息,消息里面有客户端使用的 TLS 版本号、支持的密码套件列表,以及生成的随机数(Client Random)。
TLS 第二次握手
Server Hello
服务端收到客户端的「打招呼」,同样也要回礼,会返回「Server Hello」消息,消息面有服务器确认的 TLS 版本号,也给出了一个随机数(Server Random),然后从客户端的密码套件列表选择了一个合适的密码套件。
Certificate
接着,服务端为了证明自己的身份,发送「Certificate」消息,会把证书也发给客户端。
Server Key Exchange
这一步就和 RSA 握手过程有很大到区别了,因为服务端选择了 ECDHE 密钥协商算法,所以会在发送完证书后,发送「Server Key Exchange」消息。
这个过程服务器做了三件事:
-
选择了名为 named_curve 的椭圆曲线,选好了椭圆曲线相当于椭圆曲线基点 G 也定好了,这些都会公开给客户端;
-
生成随机数作为服务端椭圆曲线的私钥,保留到本地;
-
根据基点 G 和私钥计算出服务端的椭圆曲线公钥,这个会公开给客户端。
为了保证这个椭圆曲线的公钥不被第三方篡改,服务端会用 RSA 签名算法给服务端的椭圆曲线公钥做个签名。
Server Hello Done
随后,就是「Server Hello Done」消息,服务端跟客户端表明:“这些就是我提供的信息,打招呼完毕”。
至此,TLS 两次握手就已经完成了,目前客户端和服务端通过明文共享了这几个信息:Client Random、Server Random 、使用的椭圆曲线、椭圆曲线基点 G、服务端椭圆曲线的公钥,这几个信息很重要,是后续生成会话密钥的材料。
TLS 第三次握手
Client Key Exchange
客户端收到了服务端的证书后,自然要校验证书是否合法,如果证书合法,那么服务端到身份就是没问题的。校验证书到过程,会走证书链逐级验证,确认证书的真实性,再用证书的公钥验证签名,这样就能确认服务端的身份了,确认无误后,就可以继续往下走。
客户端会生成一个随机数作为客户端椭圆曲线的私钥,然后再根据服务端前面给的信息,生成客户端的椭圆曲线公钥,然后用「Client Key Exchange」消息发给服务端。
至此,双方都有对方的椭圆曲线公钥、自己的椭圆曲线私钥、椭圆曲线基点 G。
还记得 TLS 握手阶段,客户端和服务端都会生成了一个随机数传递给对方吗?
最终的会话密钥,就是用「客户端随机数 + 服务端随机数 + x(ECDHE 算法算出的共享密钥) 」三个材料生成的。
之所以这么麻烦,是因为 TLS 设计者不信任客户端或服务器「伪随机数」的可靠性,为了保证真正的完全随机,把三个不可靠的随机数混合起来,那么「随机」的程度就非常高了,足够让黑客计算不出最终的会话密钥,安全性更高。
Change Cipher Spec
算好会话密钥后,客户端会发一个「Change Cipher Spec」消息,告诉服务端后续改用对称算法加密通信。
Encrypted Handshake Message
接着,客户端会发「Encrypted Handshake Message」消息,把之前发送的数据做一个摘要,再用对称密钥加密一下,让服务端做个验证,验证下本次生成的对称密钥是否可以正常使用,以及验证之前的握手信息是否有被中途篡改过。
TLS 第四次握手
最后,服务端也会有一个同样的操作,发「Change Cipher Spec」和「Encrypted Handshake Message」消息,如果双方都验证加密和解密没问题,那么握手正式完成。
于是,就可以正常收发加密的 HTTP 请求和响应了。