跳至主要內容

HTTPS 入门

AruNi_Lu计算机基础网络约 3947 字大约 13 分钟

本文内容

1. 什么是 HTTPS

HTTPS 全称是 HTTP over SSL/TLS,也就是运行在 SSL/TLS 协议上的 HTTP。

HTTPS 在通信之前会先通过 SSL/TLS 加密,所以它是一个 安全协议。同时,它也是建立在 TCP/IP 只上的,所以也是一个 可靠传输协议

所以 HTTPS 可以看成是 HTTP + SSL/TLS + TCP/IP。

image-20230221204317677

2. HTTP 有什么安全隐患

HTTP 一个最大的缺陷,就是使用 明文传输,也就是你传输的消息能被中间人一五一十的看见。所以 HTTPS 为了解决 HTTP 不安全的缺陷,引入了 SSL/TLS 协议,使得消息能够 加密传输

那么,HTTP 使用明文传输会有哪些安全隐患呢?只有知道了这些隐患,HTTPS 才能 “对症下药”。

HTTP 由于是明文传输,所以会存在下面几个问题:

  • 数据被 窃听,即不具有 机密性
  • 数据被 篡改,即不具有 完整性
  • 数据被 冒充,即不具有 身份认证

下面就来看看,HTTPS 是如何 “对症下药” 的。

> 插曲:加密小知识

在真正讲解 HTTPS 之前,要先知道一些加密的小知识。

加密 分为 对称加密非对称加密,它们的区别如下:

  • 对称加密:加密解密都使用 一个密钥
  • 非对称加密:有 两个密钥(公钥和私钥),公钥可以随意发放,私钥必须由本人保管。而且 这两个密钥可以双向加解密

对称加密和非对称加密各自的优缺点:

  • 对称加密 只使用一个密钥,所以 运算速度快,密钥必须保密,但是又 无法做到安全的交换密钥
  • 非对称加密 使用两个密钥,所以 运算速度慢,公钥可以随意发放而私钥必须保密,所以 避免了密钥交换问题

对称加密没什么好说的,就是普通的加密,比如,你和你女朋友面对面建群,你发起群聊时需要创建一个密码,然后你把这个密码告诉你女朋友,这样你们就可以进入同一个群聊暧昧了。

非对称加密就有意思了,它有两个密钥,而且这两个密钥是可以双向加解密的。因此根据加解密流程的不同,其目的也不一样:

  • 公钥加密,私钥解密:目的是为了 保证数据传输的机密性。因为被公钥加密的数据,其他人是无法解开的,只有持有私钥的人,才能解密得出实际的数据;
  • 私钥加密,公钥解密:目的是为了 防止数据是被冒充的。因为私钥是不可泄漏的,如果公钥能解密出私钥加密后的数据,就说明该数据是来自持有私钥的人发送的。

其实,还有一种加密方式,叫做 混合加密,只不过是 将对称加密和非对称加密结合起来使用

至于为什么要出现混合加密方式,因为对称加密和非对称加密都有缺点,而混合加密就是为了避免这些缺点的。具体的使用场景后面会讲到。

3. HTTPS 如何解决安全隐患

3.1 摘要算法—仿篡改 (完整性)

我们先不讲解如何仿窃听,因为当解决了篡改和冒充风险时,窃听自然而然就解决了。

SSL/TLS 通过 摘要算法 来实现 完整性,它能为数据生成独一无二的 “摘要” 字符串,我们通常称之为「指纹」。

为了保证数据不被篡改,摘要算法的实现如下:

  • 发送时先对数据计算出一个「指纹」,然后将这个「指纹」和数据一起传输给对方。

    注:对数据计算出来的「指纹」是无法反推出数据的

  • 对方收到数据和「指纹」后,会先对数据进行同样的计算,得出另一个「指纹」,然后将这两个「指纹」进行对比,如果相同,则说明数据没有被篡改,否则数据就被篡改过了。

上面的过程如下图所示:

image-20230221211516134

实际上,摘要算法就是一个哈希函数,所以上面的「计算」是「哈希运算」,「指纹」是「哈希值」。所以实际上的过程图如下:

image-20230221222758287

注:哈希函数是通信双方提前协商好的

所以,用哈希函数对数据进行哈希运算(摘要算法)得到一个哈希值,然后将这个哈希值和数据一起发送,就能保证数据的完整性,也就是没有被篡改过。如果被篡改,那么第三步计算出来的哈希值就与原来的哈希值不匹配。

两个问题:

通过摘要算法可以保证数据不被篡改,但是并不能保证「数据 + 哈希值」不会被中间人替换(冒充发送一个假的),因为 缺少了对数据发送方的证伪

而且 哈希函数在协商的时候,怎么保证不会被中间人窃听到呢

请带着这两个问题,继续往下看。

3.2 数字签名—仿冒充 (身份认证)

上面通过摘要算法,解决了数据被篡改的问题,但是没有解决数据被冒充的的问题,因为缺少对数据来源的证伪。

提到这个冒充问题,不知道你有没有想起上面的小插曲,在 非对称加密 中,如果加解密流程是「私钥加密,公钥解密」,那么就能 保证数据的来源是可靠的

私钥一般是服务端持有的,所以下面假设发送数据的一方是服务端,接受数据的一方是客户端。我们尝试对上面的摘要算法进行改进:

  • 服务端发送的数据在通过哈希运算得出哈希值 A 时,不直接把这个哈希值 A 发送出去,而是 先对它进行私钥加密,加密后的密文就称为「数字签名」,然后将「数字签名 + 数据」一起发送出去。

    因为非对称加密效率太低,所以只对数据的哈希值加密的话,运算量小很多,得到的数字签名也很小,方便保管和传输

  • 客户端收到「数字签名 + 数据」后,会对数据做哈希运算得出哈希值 B,然后 使用公钥(公钥会提前发放)对数字签名解密,得到哈希值 A,最后将两个哈希值进行对比。

过程如下:

image-20230221230404031

由于 私钥是服务端独有的,所以如果客户端使用公钥解密出来的哈希值 A 与哈希函数计算出来的哈希值 B 相同,则可以保证「数据 + 数字签名」是服务端发送的。

所以,通过「数字签名」,也就是非对称加密,解决了「数据 + 哈希值」被冒充的问题。

3.3 CA + 数字证书—仿冒充 (身份认证)

但是,冒充的问题真的全都解决了吗?

我们确实可以保证「数据 + 数字签名」不会被冒充,不过这个公钥能保证是来自 正确的发送方 吗?

可能你会说,我能用公钥解密得到正确的哈希值啊,怎么不能保证这个公钥是发送方的??

是,确实能保证公钥是发送方的,但是这个发送方如果是其他人呢?因为我们并 没有验证公钥的真伪

所以还可能存在这样一种场景,有一个中间人,他也有自己的一对公私钥,通信过程是下面这样的:

  • 中间人将服务端的真公钥和哈希函数拦截,然后替换成假公钥和假哈希函数发送给客户端;
  • 接着中间人使用自己的私钥做数字签名,发送给客户端;
  • 客户端收到后,用自己的假公钥(中间人的)进行解密,得到假的数据。

正是因为没有对收到的公钥和哈希函数做身份校验,所以导致上面的情况发生。

为了解决上面的问题,就需要引入一个 权威的机构 CA(数字证书认证机构)。

服务端可以先将公钥注册到 CA,CA 会用他的私钥对此公钥做个「数字签名」,然后将服务端的「个人信息 + 公钥 + 数字签名」打包成一个数字证书,返回给服务端

那么当客户端发起请求时,服务端会先把这个数字证书返回给客户端,客户端再使用 CA 的公钥校验数字证书的真伪(数字证书中的数字签名是用 CA 的私钥做的,所以 CA 的公钥能解密),如果是真的,就说明此数字证书是在 CA 注册过的,即合法的,那么就可以保证数字证书里的公钥是来自服务端的

注:CA 的公钥是提前置入到客户端的浏览器或操作系统里

提前工作如下图:

image-20230222091419334

公钥验证流程如下:

image-20230222092931139

所以,这个权威机构 CA 会先对服务器的公钥进行加密,放入数字证书中,那么只要数字证书是可信的,里面的公钥就是可信的。通过 CA 可以保证服务端的身份,解决了冒充问题。

既然公钥冒充的问题解决了,那么后面就可以 通过服务端的这对公私钥进行加密通信,自然而然就解决了数据被窃听的风险(机密性),那么哈希函数自然也能加密协商。

所以通过 CA数字证书,解决了上面的所提出的两个问题。同时,利用非对称加密(服务端的公私钥)来进行通信,解决了窃听风险。所以当解决了篡改和冒充风险时,窃听自然而然就解决了。

4. HTTPS 连接的建立

通过上面的「摘要算法 + 数字签名 + CA 的数字证书」解决了 HTTP 的三大安全问题,但是,后面的 数据传输过程需要使用非对称加密来进行

通过前面的小插曲可以知道,非对称加密算法非常慢,因为它涉及到两个钥匙的加解密,是十分复杂的。如果每次传输数据都要进行这么复杂的加解密,那传输效率也太低了

那 HTTPS 是怎么做的呢?我们可以通过「摘要算法 + 数字签名 + CA 的数字证书」来进行加密通信,那么可不可以 利用这个加密通信来生成一个会话密钥」呢?因为 加密通信能保证「会话密钥」是只有通信双方才知道的。生成之后,后面的数据传输就不用非对称加密来进行了,而是使用这个「会话密钥」,会话密钥双方是一样的,也就是对称加密,效率是比较高的

其实,HTTPS 就采用了上面的思路,先通过非对称加密协商出一个「会话密钥」,之后的数据传输就使用这个「会话密钥」对称加密传输

这也就是我们上面讲到的 混合加密,使用到了 HTTPS 通信的场景中。

下面,我们就来看看 HTTPS 从连接的建立到数据的传输流程是怎样的。

连接的建立主要是通过 SSL/TLS 协议完成的,主要的流程如下:

  1. 客户端向服务器索要数字证书,并验证其真伪,取出服务器的公钥;
  2. 双方协商出「会话密钥」;
  3. 双方采用「会话密钥」进行加密通信。

先来看看比较简单的基于 RSA 算法的 TLS 握手,握手分为四次,如下所示:

HTTPS 连接建立过程详细流程如下:

1. ClientHello

首先,客户端向服务端发起加密通信请求 ClientHello,请求中主要有:

  • 客户端支持的 TLS 版本号;
  • 客户端产生的随机数(Client Random),后面用于生成「会话密钥」的条件之一
  • 客户端支持的密码套件列表,如 RAS 加密算法。

2. ServerHello

服务端收到请求后,会向客户端发起响应 ServerHello,响应中主要有:

  • 确认 TLS 版本号,如果流程器不支持,则关闭加密通信;
  • 服务器产生的随机数(Server Random),后面用于生成「会话密钥」的条件之一
  • 确认使用的密码套件列表;
  • 服务端的数字证书

3. 客户端回应

客户端收到服务端的响应后,会先通过浏览器或操作系统中的 CA 公钥,对服务端的数字证书进行校验

如果数字证书没问题,客户端就会取出里面的公钥(服务端的),使用此公钥对报文进行加密,报文中的内容如下:

  • 个随机数(pre-master key),这个随机数会使用服务端的公钥加密,这个随机数是生成「会话密钥」的条件指一

    此时客户端就拥有了 三个随机数:Client Ranom + Server Random + pre-master key。然后计算出「会话密钥」。

  • 通知服务端,之后使用这个「会话密钥」进行通信

  • 所有握手数据的一个摘要,供服务端校验。

4. 服务端最后的回应

服务端收到客户端的报文后,会用自己的私钥解密,获取第三个随机数 pre-master key,然后同样计算出「会话密钥」,至此,服务端的密钥也生成了

接着服务端会发送最后的消息:

  • 通知客户端,之后也使用这个「会话密钥」进行通信
  • 同样把所有的握手数据做个摘要,供客户端校验。

自此,基于 RSA 算法的 TLS 握手过程就结束了,双方都拥有了同样的「会话密钥」,之后的数据通信都是使用这个对称的「会话密钥」进行加解密,也就是完全使用普通的 HTTP 协议。

基于 RSA 算法的 TLS 握手的缺陷:

RSA 算法是不支持前向保密的

因为最后一个随机数是使用公钥加密,然后服务端使用私钥解密。如果服务端的私钥一旦泄漏,那么之前被第三方所截获的所有秘密报文都会被破解

因为第三方可以根据服务端的私钥获取到最后一个随机数,进而生成这个「会话密钥」。

为了解决这个问题,后面出现了 ECDHE 算法,现在的 TLS 握手基本上都是使用的 ECDHE 算法。由于文章篇幅原因,ECDHE 算法的 TLS 握手后续再讲解。

5. 参考文章

上次编辑于: