图文详解 -- HTTPS站点的SSL证书 ,扩展SSL证书,密钥交换和身份验证机制汇

在客户端(这里指浏览器,下同)与 facebook 网站服务器进行 SSL 握手的过程中(现在称为TLS 握手,进行TLS握手前的TCP 三次握手必不可少,这里描述的场景假设已经完成了 TCP 三次握手):




首先两者协商使用什么协议连接:
第一次“往”:由客户端在一个类型为 Client Hello 的 TLS 握手包中携带客户端运行的TLS 协议版本,支持的密钥交换算法集合(加密套件列表)发送至服务器端



 ;然后客户端先验证服务器:
第一次“返”:服务器在一个类型 Server Hello 的 TLS 握手包中携带选取的特定密钥交换算法,在类型为 Certificate 的 TLS 握手包中携带自己的数字证书公钥(或层级信任关系的证书链),以及一个类型为 Server Hello Done 的 TLS 握手包发送给客户端,客户端遍历本地文件系统中的所有已导入的 CA(证书颁发机构)证书,尝试验证服务器的证书确实由其声称的那个 CA 机构所签发,如果验证失败,则提示用户该服务器证书不可信,并询问是否“手动”设置信任关系,或者拒绝,如果验证成功,不向用户显示任何信息。




然后服务器验证客户端:(上面的验证失败则中断 TLS 握手,不会进行下面的步骤)
第二次“往”:客户端用先前与服务器协商的密钥交换算法(通常为对称加密算法,如果为 RSA 则为非对称加密算法)生成一个随机密钥,它将用于两者会话的“钥匙”,然后客户端再用服务器的证书公钥来加密这个会话钥匙,并通过 Change Cipher Spec Protocol(变更密码通知协议),在一个类型为 Client Key Exchange 的 TLS 握手包中携带,发送至服务器端。
(浏览器这个加密密钥的时间开销会被用户误认为是在 HTTPS 中引入的数据传输延迟,因为在收到响应的数据并解密成明文前,整个页面都不可见)




第二次“返”:服务器收到后,用自己的证书私钥,解开这个会话钥匙(公钥加密私钥解密),如果解密失败,说明客户端的身份不可信(可能是一个中间人截获与原来的客户端通信后,伪造的,但是由于该中间人无法伪造最先两者使用的协商协议,因此服务器端也就不能用私钥解开伪造的会话密钥)
如果服务器端解密成功,则说明客户端是合法的,服务器在类型为 Change Cipher Spec Protocol 的 TLS 记录层中包含 Finished 握手包,返回给客户端,表明客户端的身份通过验证;
客户端收到通知后(解密 Finished 握手包后),开始用协商好的会话钥匙(客户端在第二次“往”中发送的随机密钥,此刻不需要再用服务器公钥加密,前面加密的目的在于验证客户端的身份)来加密并发送 HTTP 请求;服务器用相同的会话钥匙解密并读取 HTTP 请求,加密并返回 HTTP  响应,浏览器用会话钥匙解密并读取 HTTP 响应。。。如此反复,构成完整的 HTTPS 通信流量。



在早期,客户端浏览器进程在控制 CPU 加解密 HTTPS 流量,以及服务器端 web 服务器进程在控制 CPU 加解密 HTTPS 流量时,都会造成一定的计算时间开销,并且引入额外的网络传输延迟,而现在的客户以及服务器端应用的并发模型高效利用多核,高速 CPU 的计算优势,这些延迟多数情况已经不太明显了。

总结下来,TCP 3次握手需要一次“往返”,TLS 握手协商交换密钥,验证双方身份,需要两次“往返”,因此在实际开始传输应用层数据(请求和响应页面)前,需要等待三次往返造成的时间开销,早期这个时间开销更多地取决于 CPU 的计算能力与客户/服务应用的编程模型,现在则更多地取决于客户与服务器端的物理距离,骨干网络的带宽与当前负载,是否采用 CDN 内容分发网络的加速访问技术等等因素。

TLS 握手结束后,即开始传输应用数据,此时,浏览器根据用户提交的内容生成 HTTP 请求,其内置的 SSL/TLS 模块将 HTTP 请求作为有效载荷,封装在称为 “TLS 记录层”的数据包中,每个这样的数据包大小上限为 16 KBytes,通常,一个 HTTP 请求的内容远小于 16 KBytes,因此能够封装在一个大小约为 1.4 KBytes 的 TLS 记录层中,还可以对请求或响应数据进行压缩(可选),并且为该TLS 记录层计算并添加最多 32 字节的信息验证码(MAC,类似于校验和,必选。服务器端接收并解密 TLS 记录层中的数据后,计算其中的 MAC,将计算结果与层中携带的 MAC 字段值对比,验证该层数据的完整性与可靠性,防止 TLS 记录层在传输过程中数据丢失,或者被篡改,这都会造成 MAC 值改变);浏览器的 SSL/TLS 模块使用先前协商好并生成的随机密钥来加密这个 TLS 记录层数据包,传递给操作系统的 TCP/IP 协议栈,后者依序添加 TCP 头部成为 TCP 分段;添加 IP 头部成为 IP 分组;最后封装成一个大小约 1.5 KBytes(链路层 MTU上限)的以太网帧,然后传递给服务器端。(1.5K 字节扣掉20字节的 IPv4 头部,20字节的 TCP 头部,40字节的 TCP 选项,等于 1.42K 字节,这就是常见的单个 TLS 记录层数据包大小,超过这个大小的 TLS 记录层数据包,就需要封装成多个以太网帧,准则是不超过链路层 MTU 上限)


服务器端操作系统的 TCP/IP 协议栈以相反顺序解封装从链路层到传输层的头部,然后将“裸露”出来的 TLS 记录层数据包交给 web 服务器的 OpenSSL 模块进行解密,后者计算并验证其 MAC 字段,MAC 验证通过后,才将 HTTP 请求数据交给 web 服务器的请求处理与响应模块,后者以类似浏览器在构建请求时的步骤将 HTTP 响应作为有效载荷封装在 TLS 记录层 中传递。

但是细节稍有不同。HTTP 响应体中的大型 HTML 页面或者流媒体,其数据量往往超过每个 TLS 记录层的 16 KBytes 上限,例如 youtube 站点要通过 HTTPS 传输加密的 1.6 MBytes 的视频流数据至客户端,那么必须划分成 100 个 16 KBytes 的TLS 记录层数据包,每个数据包中的流媒体片段作为有效载荷,占据了 15 KBytes 以上的空间,剩余的几十字节才是TLS 记录层数据包本身的各种头部字段,例如记录层类型,版本,MAC 等字段。同样的,每个TLS 记录层数据包在到达传输层后,被分割成约 10~13个大小约为 1.4 KBytes 的 TCP 分段,最终结果是,产生 1000 多个以太网来传输这1.6 MBytes 的视频内容。

这里的关键是,既然每个“满载”的TLS 记录层数据包被分割成 10 几个 TCP 分段,那么浏览器必须接收到属于同一个TLS 记录层数据包的所有 TCP 分段后,才有办法解密数据并且还原其中的视频片段,但是这些 TCP 分段在因特网上传输时,难免会有传输延迟,到达客户端的时间顺序不一致,数据损坏以及丢失的情况发生,这都会导致浏览器等待服务器端重传 TCP 分段而延迟,缓冲视频的播放。可以这么讲,相较于普通的 HTTP 视频站点,使用 HTTPS 提供视频服务的站点“性能”更依赖于整个因特网的稳定性,以及地区性骨干网的带宽,当前负载状况等因素。

对于提供非视频流服务的 HTTPS 站点而言,通常可以在一个 TCP 分组中封装完整的 TLS 记录层数据包,而不是由多个 TCP 分组来构成一个完整的TLS 记录层数据包

最后,由于 TLS 技术在服务器端的实现关键依赖于 OpenSSL ,因此查阅 OpenSSL 模块的安装文档,访问官方站点(https://www.openssl.org/)查找信息,可以了解到一些与设置TLS 记录层数据包大小相关的信息。



下面列出关于 SSL 与 TLS 的一些参考信息,使用 wireshark 分析捕获的 HTTPS 数据包时,这些信息尤其适用:


SSL 握手协议版本(wireshark 过滤表达式为 ssl.handshake.version)

0xfefd    (DTLS 1.2)
0xfeff    (DTLS 1.0,数据报传输层安全,实现在 UDP 协议之上的 TLS)
0x100    (OpenSSL pre 0.9.8f)
0x303    (TLS 1.2,2008年9月发布)
0x302    (TLS 1.1,2006年4月发布)
0x301    (TLS 1.0,由 IETF 将 SSL 3.0 升级并标准化后的公开版本)
0x300    (SSL 3.0,网景公司专有协议)
0x2    (SSL 2.0 ,网景公司专有协议)

TLSv1.2 支持的记录层类型 (wireshark 过滤表达式为 ssl.record.content_type):

变更密码通知协议(Change Cipher Spec Protocol):20
加密警告(Encrypted Alert):21
握手协议(handshake protocol):22
应用层数据协议(Application Data Protocol):23

TLSv1.2 支持的握手协议(handshake protocol)类型(Handshake Type): 

Hello Request (0)
Client Hello(1)
Server Hello (2)
New Session Ticket (4)

会话记录单类型,如果浏览器在第一次“往”的 Client Hello TLS握手包中,添加了支持会话记录单的扩展字段:


那么服务器将在第二次“返”中发送该类型的 TLS 握手包,其中携带了本次 TLS 握手中的所有协商数据:密钥交换算法,客户与服务器共享的用于加密通信数据的钥匙等等。并且使用只有服务器能够解密的密钥加密,如此一来,New Session Ticket 类型的 TLS 握手包中的数据就可以安全的发送并存储在客户端:


假设后续访问站点需要建立一个新的 TLS 会话,浏览器就可以在一开始的 Client Hello TLS 握手包的 Session Ticket 字段中携带会话记录单返回给服务器,服务器解密其中的数据,这样直接就完成并简化了一次 TLS 会话的建立。(不用重新协商密钥交换算法,浏览器不用重新生成随机共享密钥,节省了双方的判断与计算量以及由此浪费的时间)


用最简单的理解方式,会话记录单就类似 cookie,在客户端保存特定 TLS 会话数据,使得该客户端后续新的 TLS 会话可以快速建立,只不过这个 “cookie”是加密的,而且实现在应用层之下,传输层之上。


Certificate(11)
Server Key Exchange (12)
Server Hello Done (14)
Client Key Exchange (16)
Encrypted Handshake Message


https://www.google.com.tw/






https://mail.google.com/






从上面的截图可以看到,gmail 使用新的传输层协议:QUIC,在 Chrome 的地址栏输入“chrome://net-internals/#quic” 即可查看浏览器当前打开的所有 QUIC 会话:




https://www.mozilla.org/zh-CN/firefox/new/






https://support.portswigger.net/







https://www.baidu.com/








https://msdn.microsoft.com/zh-cn





最后要提一点,在上面这些站点中,facebook 在 HTTPS 方面的安全配置做得最好,此话怎讲? 

例如,我们下载并且安装了 BurpSuite 开发公司的 SSL 证书(PostSwigger CA)作为本地操作系统上的“受信任的根证书颁发机构”:



,那么原则上 BurpSuite 将在浏览器与服务器中间充当 SSL 代理,当浏览器与 facebook 进行 TLS 握手时, BurpSuite 拦截浏览器的 TLS client hello 握手包,修改一些密钥交换参数,(其中的密钥交换算法,TLS 版本协商均可以在 BurpSuite 中配置):



;然后 BurpSuite 转发 TLS client hello 握手包到 facebook 服务器,冒充浏览器与服务器协商各种加密参数,并且进行密钥交换,这样 BurpSuite 就可以“剥掉”与 facebook 的加密流量并通过其接口显示给用户(还记得吗,之前我们用 wireshark 捕获的 HTTPS 流量是加密的,不能查看明文),BurpSuite 接收到服务器发送的证书后,用自己的 PostSwigger CA 根证书对 facebook的服务器证书“重签名”,这样,原本签发 facebook 证书的证书颁发机构,就变成了 PostSwigger CA (参考上图的“签发给”与“签发者”),然后将 Certificate 握手包转发给客户端。这都是为了取得浏览器的信任,然后浏览器会将 BurpSuite 当成 facebook 服务器(接受证书),无顾虑的与其进行 HTTPS 通信。如此一来,BurpSuite 就能够在中间透明地解密,转发 HTTPS 流量,并向用户显示解密后的信息。这就是 SSL 代理能够“剥掉”SSL 流量的原因。

上面这一招对普通的 HTTPS 站点有效,例如 https://www.google.com.tw ,但是对 facebook 则无效,因为 facebook 使用了“HTTPS 严格传输安全”(HTTPS Strict-Transport-Security,HSTS),强制要求浏览器使用 HTTPS 与其进行通信,不能提供给用户忽略有问题的证书的选项。而实际上也是如此,在使用 BurpSuite 充当中间 SSL 代理时,Chrome 与 FireFox 都不会“上当”,它们知道服务器(BurpSuite )返回的证书是伪造的,因此拒绝与其建立 HTTPS 连接,并且遵循 HSTS 规范,禁止用户忽略有问题的证书:



但是唯有 IE 例外,它还向用户提供忽略选项,甚至最新版本也是如此,这就给我们用 BurpSuite “欺骗”IE 提供了机会,最终 BurpSuite 可以捕获并解密 IE 与 facebook 之间的 HTTPS 流量。取代 wireshark 完成任务:


最后,使用 BurpSuite 拦截 IE 与 facebook 站点之间的 HTTPS 流量时,我们可以“实时”修改 facebook 返回的 HTTPS 响应,去掉其中的 Strict-Transport-Security 响应头部及其值,然后转发给浏览器,这样可以观察 IE 对于该响应头的处理方式:



持续更新中。。。


你可能感兴趣的:(gmssl)