title: 网络安全科普:详解 HTTPS 与 TLS layout: post thread: 286 date: 2022-12-25 author: Joe Jiang categories: Document tags: [HTTPS, TLS, mTLS, DTLS, SSL, CA, 证书, 网络安全, HTTP] excerpt: 作为普通用户,当我们上网冲浪时,是否想过为什么越来越多的域名输入时是 HTTPS 开头而非 HTTP 么?HTTPS 相比 HTTP 多出来的 S 到底多了些什么?TLS 和 SSL 又是什么,握手机制是如何进行的?其在七层协议中处于什么位置,与 HTTPS 相关的概念比如 CA 证书、Keyless、DTLS、mTLS 又分别是些啥?当我们使用 wireshark 时又该怎么抓包分析……种种疑问,希望能通过这篇文章的介绍为大家解答其中的部分解惑。 toc: true header: image: ../assets/in-post/2022-12-25-HTTP-and-TLS-Teaser.png
现在的网站都推荐使用 HTTPS 来确保用户数据的安全,验证网站的所有权,防止攻击者创建虚假网站版本,以及将信任传达给用户。如果网站要求用户登录、输入个人详细信息(例如其信用卡号)或查看机密信息(例如,健康福利或财务信息),则必须对数据保密。
作为普通用户,当我们上网冲浪时,是否想过为什么越来越多的域名输入时是 HTTPS 开头而非 HTTP 么?HTTPS 相比 HTTP 多出来的 S 到底多了些什么?TLS 和 SSL 又是什么,握手机制是如何进行的?其在七层协议中处于什么位置,与 HTTPS 相关的概念比如 CA 证书、Keyless、DTLS、mTLS 又分别是些啥?当我们使用 wireshark 时又该怎么抓包分析……种种疑问,希望能通过这篇文章的介绍为大家解答其中的部分解惑。
超文本传输协议 (Hypertext Transfer Protocol, HTTP) 是设计用于在 Web 上传输内容的协议。 HTTP 是一种简单协议,它利用可靠的传输控制协议 (Transmission Control Protocol, TCP) 服务来执行其内容传输功能。由于数据在传输过程中是明文传输,因此无法保证网络通信在传输过程中不被篡改,安全性受到限制。
超文本传输安全协议 (HTTPS) 是 HTTP 的安全版本,但 HTTPS 并不是独立于 HTTP 的协议。它只是在 HTTP 协议的基础上使用 TLS/SSL 加密。HTTPS 经过加密,以提高数据传输的安全性。
HTTPS 使用加密协议对通信进行加密。该协议称为传输层安全性 (TLS),但以前称为安全套接字层 (SSL)。该协议通过使用所谓的非对称公钥基础架构来保护通信。这种类型的安全系统使用两个不同的密钥来加密两方之间的通信:
HTTPS安全是由一套安全机制来保证的,主要包含这4个特性:机密性、完整性、真实性和不可否认性。
SSL(Secure Socket Layer)是指安全套接字层,简而言之,它是一项标准技术,可确保互联网连接安全,保护两个系统之间发送的任何敏感数据,防止网络犯罪分子读取和修改任何传输信息,包括个人资料。TLS(Transport Layer Security,传输层安全)是更为安全的升级版 SSL。
TLS 1.0 版实际上最初作为 SSL 3.1 版开发,HTTPS 是在 HTTP 协议基础上实施 TLS 加密,所有网站以及其他部分 web 服务都使用该协议。因此,任何使用 HTTPS 的网站都使用 TLS 加密。
使用了 SSL/TLS 之后,因为数据被非对称加密手段加密了,即使被截获,也是获取不到信息的。
TLS 协议实现的功能有三个主要组成部分:加密、认证和完整性。
网站或应用程序要使用 TLS,必须在其源服务器上安装 TLS 证书(由于上述命名混淆,该证书也被称为 SSL 证书),而 TLS 连接是通过一个称为 TLS 握手的流程启动的,在这个过程中用户设备会和服务器交换确定信息,这些信息包括要使用的 TLS 版本、密码套件、TLS 证书、会话密钥等等。
而在浏览器端,当用户访问服务器页面的时候,浏览器会检查服务器的 SSL/TLS 许可是不是可用的,不可用的话,会提醒用户,这个网站不安全,也就是访问的数据可能被黑客截获;此时用户可以根据判断来不访问这个界面;许可都齐全的话,便可以安全的进行数据交互。
具体来说,SSL/TLS 在工作流程中通过如下三个方面保证安全性:
为了方便大家阅读,特在此章将全文涉及到的一些专业术语进行整理,整理此术语表供大家查阅。
简称 | 英文全称 | 中文全称 |
---|---|---|
CA | Certificate Authority / Certification Authority | 证书颁发机构 |
SSL | Secure Sockets Layer | 安全套接字层协议 |
TLS | Transport Layer Security | 传输层安全性协议 |
PKI | Public key infrastructure | 公钥基础设施 |
PCA | Private Certificate Authority | 私有证书颁发机构,又名私有 CA |
HTTP | Hypertext Transfer Protocol | 超文本传输协议 |
HTTPS | Hypertext Transfer Protocol Secure | 超文本传输安全协议 |
- | Public key | 公钥 |
- | Private key | 私钥 |
OSI | Open Systems Interconnection | 开放网络互联模型 |
TCP | Transmission Control Protocol | 传输控制协议 |
DTLS | Datagram Transport Layer Security | 数据包传输层安全性协议 |
mTLS | Mutual Transport Layer Security | 双向 TLS |
DH | Diffie-Hellman key exchange | 迪菲-赫尔曼密钥交换 |
- | premaster secret | 预主密钥 |
HTTP 协议是用于从网络传送超文本数据到本地浏览器的传送协议,HTTPS 协议简单讲是 HTTP 的安全版,在 HTTP 协议的基础上加入 SSL 层。
其中,HTTP的端口号为80, HTTPS的端口号为443,两者均为应用层协议,在 OSI 七层模型的最上层。
在 HTTPS 的工作流程中,一个重要的角色便是证书,他的正常运行需要有一个证书(CA 证书):由专门的证书机构颁发。在知道了 TLS 的握手流程后,我们来看看证书在其中所起到的作用。
当客户端向服务端发送请求,请求中会向服务器提供以下信息:客户端支持的协议版本,比如TLS 1.0 版,此后,服务器返回经过 CA 认证的数字证书,证书里面包含了服务器的 public key,接下来证书在客户端的工作流程如下:
关于 TLS 证书/CA 证书的更多细节,可以参见文章《奇妙的 SSL/TLS 证书》,本文不再深入探讨。
HTTPS 连接建立过程和 HTTP 差不多,区别在于 HTTP(默认端口 80) 请求只要在 TCP 连接建立后就可以发起,而 HTTPS(默认端口 443) 在 TCP 连接建立后,还需要经历 SSL 协议握手,成功后才能发起请求。
在 TLS1.2 以前,需要2-RTT时间进行握手,我们具体来看每一步操作:
在客户端和服务器之间进行了两次往返(2-RTT)以完成握手。 平均而言,这需要0.25秒到0.5秒之间的时间。而这只是握手过程,实际的数据传输还没有开始。我们绘制示意图如下解释如上流程:
TLS1.3 在握手上做了优化,只需要一次时延往返就可以建立连接(1-RTT),其握手基本步骤为:
TLS 1.3 的核心宗旨是简单性。在新版本中,除去了 Diffie-Hellman(DH)密钥交换以外的所有密钥交换算法。简而言之,DH 算法(Diffie-Hellman 算法)可以保证在双方不直接传输原始密钥的情况下,完成双方密钥交换。
TLS 1.3 还定义了一组经过测试的 DH 参数,无需与服务器协商参数。由于只有一个密钥交换算法(具有内置参数)和少数支持的密码,因此设置 TLS 1.3 通道所需的绝对带宽比早期版本要少得多。示意图流程如下:
DTLS 是基于 UDP 场景下数据包可能丢失或重新排序的现实情况下,为 UDP 定制和改进的 TLS 协议。
DTLS 协议由两层组成: Record 协议 和 Handshake 协议
与 TLS 的握手流程相比,DTLS 的握手流程存在如下几点差异(左为 TLS 握手,右为 DTLS 握手):
在实现机制上,DTLS 还存在几个特点,首先是握手防护机制,在这个机制中,除了上文说到的防止被攻击等在握手阶段引入的改进措施外,还有一个机制叫重传:
以握手的第一阶段举例,客户端发送 Client Hello(不带 Cookie,区别于握手流程中的第二次 Client Hello)之后,启动一个定时器,等待服务端返回 HelloVerifyRequest,如果超过了定时器时间客户端还没有收到 HelloVerifyRequest,那么客户端就会知道要么是 Client Hello 消息丢了要么是 Hello Verify Request 消息丢了,客户端就会再次发送相同的 Client Hello 消息,即使服务端确实发送了 Hello Verify Request 还是收到了 Client Hello 消息,它也知道是需要重传,并再次发送 Hello Verify Request 消息,同样地,服务端也会启动定时器来等待下一条消息。
由于 DTLS 依赖 UDP,而 SSL/TLS 依赖 TCP,所以两者在加密方式上存在如下差异:
DTLS 主要被用在 WebRTC 协议中,以保证媒体传输的安全性。
在基础的 TLS 认证流程中,大量的场景都是确保用户访问的是真正的服务方,如:银行、电商网站等等,即保证用户不会被钓鱼网站或是中间人攻击,此时我们只需要在客户端侧对服务端身份进行校验。
在典型的 SSL 连接场景中,通过 HTTPS 连接到服务器的客户端会检查服务器的有效性,它会在启动 SSL 握手时检查服务器返回证书的有效性。但是,有时你可能希望将服务器配置为对与其连接的客户端进行身份验证。这样,你便可以只允许使用证书进行身份验证的用户访问 web 服务器上的资源。
启用客户端身份校验的两个基本步骤:
由于客户端安装证书的不方便性、成本高以及双因素身份验证的快速推行,客户端身份验证并没有得到广泛使用。
很多时候,比如在一些支付场景下,我们和支付机构、商户构成的三者关系中,在商户和支付机构间需要保证相互的身份认证,以保证支付信息在两者间正常流转,这时便需要我们使用双向认证,即相互 TLS。
相互 TLS,简称 mTLS,是一种相互身份验证的方法。mTLS 通过验证他们都拥有正确的私人密钥来确保网络连接两端的各方都是他们声称的身份。他们各自的 TLS 证书中的信息提供了额外的验证。
一个典型的 TLS 流程应该包含如下几步:
相比之下,mTLS 会在客户端验证服务器证书后加上几步,以保证服务端可以对客户端身份进行验证,并授予访问权限,一个完整的 mTLS 流程如下:
由于公共互联网上亟待解决的问题是防止被访问的网站内容被篡改,保证用户不会访问到钓鱼网站;此外,再加上将 TLS 证书分发到所有终端用户设备上是非常困难的现状,mTLS 并没有被运用到整个互联网。mTLS 对于较小范围内的组织验证和通信非常有用,除了验证信息外,他还可以防止各种类型的攻击,比如在途攻击、网络钓鱼攻击以及恶意 API 请求等等。
mTLS 通常被用于零信任安全框架,以验证组织内的用户、设备和服务器。它也可以帮助保持 API 的安全。
虽然 HTTPS 可以解决传输的安全性但是引入了私钥的安全和管理问题。只要拿到了私钥,HTTPS 就如同虚设。尤其是在传统 CDN 加速场景下,需要将私钥证书同步给 CDN,无形中增加了风险,所以诞生了 Keyless 技术。这项技术可以使得客户在使用 CDN 进行 HTTPS 加速时保留其自身 SSL 的私钥,在仅有公钥的场景下顺利完成 SSL 握手。
在 Keyless 的作用下,服务端不解密密文,而是将经加密后的预主密钥(premaster secret)等数据打包发送给远端 key server,由其进行加工并返回数据;针对 DH 协商密钥的流程,服务端则负责将 DH 参数、服务端随机数、客户端随机数等数据传给 key server,由 key server 处理后返回 DH 数据以及证书等信息。
以 CloudFlare 为例,我们看看 Keyless 在部署时有设计哪些额外的流程以保证安全。为了使 Keyless SSL 安全,CloudFlare 边缘到 key server 的连接也需要安全。key server 可以为所有能够访问它的人提供私钥操作,就像一个密码数据库。保证只有 CloudFlare 可以访问 key server 来执行操作对 Keyless SSL 至关重要。
CloudFlare 通过相互认证的 TLS 机制来保证 CloudFlare 和 key server 之间的连接安全。在握手环节一章,我们提到了客户端对服务端的单方向身份认证,是通过验证 CA 证书来进行的,而后我们也提到了客户端身份校验,这在这里便派上了用场。在 TLS 双向认证中,客户端和服务端都由对方的证书并相互认证。
在 Keyless SSL 中,key server 仅允许携带 CloudFlare 内部签发的证书的连接。CloudFlare 使用我们自己签发的证书来进行双向认证。
在这里,我们以 RSA 为例,如下两图展示了在接入 Keyless 前后,TLS 握手过程的变化差异。
本文介绍的各类协议均有对应的 RFC 标准,罗列于此供读者参考:
利用 wireshark 我们可以对 https 流量进行抓包分析,下载地址见 https://www.wireshark.org/#download
通过 Wireshark 我们可以很好的过滤 HTTPS 流量,比如如下常见的几个过滤条件:
// TLS加密传输数据的过滤器
ssl.record.content_type == 23 and tcp.dstport == 443
// TLS 建立连接
ssl.handshake.type == 1
// 在知道 IP 地址为A时的指定 TLS 流量
ip.addr == A && tcp.port == 443
但对于 HTTPS 流量,如果需要解密,我们还需要增加如下几个步骤来达成目的:
tls && ip.addr=1.1.1.1
来过滤指定 tls 流量;通过 Wireshark 抓包,以一个 TLS1.2 版本的 ClientHello 消息报文内容为例,我们可以看到其中包含了客户端支持的 TLS 版本、加密套件、以及用于连接的 SNI 等信息
同样的,以一个 TLS1.2 版本的建立连接为例,我们可以看到 Server 在返回 Server Hello 之后还返回了证书、Server Key Exchange 以及 Server Done 等信息
用过抓包工具的人都知道,比如 Charles,Fiddler 是可以抓取 HTTPS 请求并解密的,它们是如何做到的呢?
简单来说,Charles 作为一个“中间人代理”,当浏览器和服务器通信时,Charles 接收服务器的证书,然后动态生成一张证书发送给浏览器,也就是说 Charles 作为中间代理在浏览器和服务器之间通信,所以通信的数据可以被 Charles 拦截并解密,这包括服务器证书公钥和 HTTPS 连接的对称密钥。
由于 Charles 更改了证书,浏览器校验不通过会给出安全警告,所以 Charles 可以正常工作的前提在于必须安装 Charles 的证书,使系统信任。
在本地开发功能模块时,可能有些 Web API 前置要求环境为 HTTPS,这要求我们在本地开发环境也能够配置 HTTPS,OpenSSL 是 SSL 和 TLS 协议的开放式源代码实现,使用它,我们可以在本地生成一个自签名证书,以方便开发。如下一行命令可以帮助我们生成一个 HTTPS 证书以及私钥:
openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem
社区里有一个开源库叫 mkcert,可以更便捷的为你生成 TLS 证书,这里不深入介绍,感兴趣可以移步 https://github.com/FiloSottile/mkcert 查看更多。
注:为了能够正常使用,本地生成的证书需要被加入信任列表才能正常使用。