HTTPS

警告
本文最后更新于 2024-01-23,文中内容可能已过时。

HTTPS

HTTPS 全称是 HTTP over SSL,也就是通过 SSL/TLS 加密 HTTP 数据,这或许是 SSL 最广泛的应用。

SSL/TLS 协议简单介绍

参考:吐血整理,HTTPS 看这篇就够了,一次给你说个明白-CSDN 博客,这篇博客里详细介绍了TLS协议,非常值得参考

HTTPS 是身披 SSL/TLS 外壳的 HTTP 协议,它并非一个新的协议而是在 HTTP 的基础上新增了安全层 (SSL/TLS),HTTPS 先和安全层通信,然后安全层和 TCP 层通信。

TSL 位于 TCP 和 HTTP 之间,即在传输层上

TLS 全称传输安全层协议,Transport Layer Security Protocol,TLS/SSL 是一种加密通道的规范。 SSL 全称 Secure Sockets Layer 安全套接字协议

TLS/SSL的发展历史

版本 描述
SSL 1.0 存在严重的安全漏洞,从未公开过
SSL 2.0 在 1995 年 2 月发布,但是存在数个严重的安全漏洞很快被 3,0 替代
SSL 3.0 1996 年发布
TLS 1.0 IETF 对 SSL3.0 进行了标准化,并添加了少数机制 但是几乎和 SSL3.0 一样
TLS 1.1 在 RFC 4346 中定义,2006 年 4 月发布
TLS 1.2 在 RFC 5246 中定义 2008 年 8 月发布
TLS 1.3 在 RFC 8446 中定义,于 2018 年 8 发表。

TLS 协议是由 TLS 记录协议和 TLS 握手协议叠加而成的

记录协议:TLS Record protocol

  • TLS 记录协议位于 TLS 握手协议的下层,是负责使用对称密码进行加密通信的部分

  • 加密使用的秘钥,是通过握手协议在服务端和客户端之间协商决定的

握手协议:TLS Handshaking Protocols

  • 由 TLS Change Ciper Spec Protocol(密码规格变更协议) 和 TLS ALert Protocol(警告协议) 组成

  • 负责在客户端和服务器之间协商决定密码算法和共享秘钥

  • 密码规格变动协议负责向通信对象传达变更密码方式的信号,协议中途发生错误时,就会通过警告协议传达给对方。

  • 警告协议是 TLS 握手协议负责在发送错误时将错误传达给对方。

由于有了传输安全层 TLS,所以 HTTPS 比 HTTP 的安全性大幅提高

  • TLS Record Protocol 保证了数据的隐私性和完整性

  • TLS Handshaking Protocols 实现了身份认证。


HTTPS 的通信过程

完整的 HTTPS 的流程图:

GitHub - ByteByteGoHq/system-design-101

其中,跟 HTTP 相比,多出来的中间那一段儿是 TLS/1.2 的握手过程,不过注意,其中只有客户端对服务端的单向验证。

HTTPS (HTTP Secure) 是使用了 SSL/TLS 协议进行加密处理的 HTTP。TCP 握手之后的通信过程大致可以分为两个阶段:SSL/TLS 握手和 HTTP 请求/响应交换。

https 的工作流程详解 - sword0077 - 博客园

吐血整理,HTTPS 看这篇就够了,一次给你说个明白_ssl_ciphers sha1-CSDN 博客完整的HTTPS的通信过程小节详细介绍了TSL/1.2的细节

  1. SSL/TLS 握手

    1. 客户端向服务器发起连接请求:客户端发送 “Client Hello” 消息给服务器,包括客户端支持的 SSL/TLS 版本号(TLS Versiion)、一个客户端生成的随机值(Client random)R1、客户端支持的加密方法列表(Cipher Suite)等信息。

    2. 服务器响应:服务器收到 “Client Hello” 后,选择一个客户端也支持的加密方法(Cipher Suite)和最高版本的 SSL/TLS 协议(TLS Versiion),然后产生一个随机值(Server random)R2,并返回 “Server Hello” 消息给客户端。

    3. 服务器提供凭证:服务器会向客户端发送其证书(包含服务器的公钥)和 “ServerHello Done” 消息。证书通常由受信任的证书颁发机构(CA)签名。

      关于 CA 签发证书的具体过程,请看《SSH 证书登录》

    4. 客户端验证证书并生成密钥:客户端验证服务器的证书是否被可信的 CA 签名,确认服务器真正拥有公钥。然后,客户端会生成一个预主密钥(Pre-Master Secret)R3,并使用服务器的公钥进行加密然后发送给服务器。

    5. 生成会话密钥:服务器使用自己的私钥对预主密钥 R3 进行解密,得到真正的预主密钥 R3。然后,客户端和服务器使用相同的方式,各自同时使用客户端随机值 R1、服务器随机值 R2 和预主密钥 R3 这三个值,生成会话密钥(Session key)。这个会话密钥用于接下来的会话加密。

    6. 客户端发出握手结束通知:客户端向服务器报告握手结束,并使用会话密钥加密这个消息。到此为止,SSL/TLS 握手过程结束。

  2. HTTP 请求/响应交换

    1. 发送请求:SSL/TLS 握手结束后,客户端就可以开始向服务器发送 HTTPS 请求了。请求中的所有内容,包括 HTTP 头、请求体等,都会使用在 SSL/TLS 握手过程中生成的会话密钥进行加密。

    2. 服务器响应:服务器接收到加密的 HTTPS 请求后,使用会话密钥对其进行解密,然后处理请求并生成响应。然后,服务器使用同样的会话密钥加密 HTTP 响应,并将其发送给客户端。

    3. 客户端处理服务器响应:客户端收到响应后,使用会话密钥解密 HTTP 响应,然后处理响应。

这个过程确保了整个会话的秘密性和完整性,因为所有的请求和响应都是加密的,防止了中间人攻击和窃听。同时,SSL/TLS 握手过程中的证书验证还提供了服务端的身份验证,保证了你正在与正确的服务器进行通信。

HTTPS 默认采用 443 端口,HTTP 协议默认采用 80 端口,注意不要弄混了。当我们配置自己的服务器通过 HTTPS 进行通行的时候,需要在对应的端口上配置证书,否则客户端将无法通过 HTTPS 协议连接此端口。

如何启用 HTTPS

首先,我们需要获取 TSL 证书,关于如何获取证书,请参考《如何获取 SSL/TSL 证书并自动续期》。

在 Nginx 中配置 HTTPS 的方法很简单,效果非常好,直接转发即可,可见转发给 HTTP 的请求,是解密过后了的,而不是未解密的。而且代理也是双向的,既代理发送到上游的流量,也代理从上游发出的流量。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
http {
    ......
    server {

        # 对外以 9090 提供 HTTPS 服务
        listen       9090 ssl ;
        listen       [::]:9090 ssl ;
        server_name  _;

        #  证书地址
        ssl_certificate "/etc/host_ssl/xiashuo.xyz.pem";
        ssl_certificate_key "/etc/host_ssl/xiashuo.xyz.key";
        #  SSL 配置
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        ssl_ciphers HIGH:!aNULL:!MD5;

        location / {
            # 被代理的,原本的 HTTP 服务
            proxy_pass http://localhost:90;
        }
    }

}

其中,ssl_certificatessl_certificate_key配置的是就是证书

在集群系统中,一般我们都会通过 Nginx 对外统一提供服务,在集群内部服务与服务之间,都是通过 HTTP 相互提供服务,而当这些服务要通过 Nginx 对外提供服务的时候,会通过另一个带 TSL 证书的接口代理处理出去,以提供 HTTPS 服务,在集群内部通过 HTTP 相互通信的主要原因是 TSL 握手是很耗时的,而且加密解密也影响效率,而且集群内部都是相互信任的,没有必要加密。

如何在抓包之后解密 HTTPS

当我们在 Chrome 浏览器中以 HTTPS 访问了一个网页,打开开发者工具,在Network中,点击这个 HTTPS 协议的请求,查看HeadersResponse,我们可以直接看到明文信息,不是说 HTTPS 协议会进行加密吗?为什么我们可以看到明文呢?这是因为 Chrome 浏览器会保存建立 TSL 握手过程中的密钥(关于如何 TSL 握手,请看HTTPS 的通信过程小节),然后自动为你解密。

但是如果我们在别的 Chrome 以外的抓包工具中捕获到 HTTPS 网络包了,就没人为我们自动解密了,我们需要手动配置解密,

首先,我们需要配置一个环境变量,让 Chrome 将预主密钥(Pre-Master Secret)输出到一个日志文件中。然后,其他的工具,比如抓包工具 wireshark,可以通过这个日志文件里的秘钥再结合自己从网络包获取的其他值,来解密网络包,实际上 Wireshark 抓取 HTTPS 协议的包的时候就是通过这种方式解密的。

关于 Wireshark 如何解密 HTTPS 协议的包,请看《抓包工具》的常见抓包场景

0%