HTTPS

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,所以 HTTPS 比 HTTP 的安全性大幅提高


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 签发证书的具体过程,请看 TSL证书 和 ssh_ca

    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 协议连接此端口。

服务端需要向客户端发送证书而客户端不需要向服务端发送证书

服务端证书的主要目的是为了:

  1. 服务端发送证书:服务端向客户端发送自己的数字证书(包含公钥和其他信息)。
  2. 客户端验证证书:客户端检查证书的有效性(比如是否被可信的证书颁发机构签署、是否过期等)。
  3. 密钥协商:客户端使用服务端的公钥加密密钥协商信息,并发送给服务端。服务端使用私钥解密,双方生成共享密钥。
    客户端通常不需要向服务端发送证书,因为:

如何启用 HTTPS

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

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

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_certificate 和 ssl_certificate_key 配置的是就是证书

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

如何在抓包之后解密 HTTPS

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

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

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

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