learn.lianglianglee.com/专栏/透视HTTP协议/26 信任始于握手:TLS1.2连接过程解析.md.html
2022-05-11 19:04:14 +08:00

743 lines
30 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>26 信任始于握手TLS1.2连接过程解析.md.html</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/专栏/透视HTTP协议/00 开篇词To Be a HTTP Hero.md.html">00 开篇词To Be a HTTP Hero.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/01 时势与英雄HTTP的前世今生.md.html">01 时势与英雄HTTP的前世今生.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/02 HTTP是什么HTTP又不是什么.md.html">02 HTTP是什么HTTP又不是什么.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/03 HTTP世界全览与HTTP相关的各种概念.md.html">03 HTTP世界全览与HTTP相关的各种概念.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/04 HTTP世界全览与HTTP相关的各种协议.md.html">04 HTTP世界全览与HTTP相关的各种协议.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/05 常说的“四层”和“七层”到底是什么?“五层”“六层”哪去了?.md.html">05 常说的“四层”和“七层”到底是什么?“五层”“六层”哪去了?.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/06 域名里有哪些门道?.md.html">06 域名里有哪些门道?.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/07 自己动手搭建HTTP实验环境.md.html">07 自己动手搭建HTTP实验环境.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/08 键入网址再按下回车,后面究竟发生了什么?.md.html">08 键入网址再按下回车,后面究竟发生了什么?.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/09 HTTP报文是什么样子的.md.html">09 HTTP报文是什么样子的.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/10 应该如何理解请求方法?.md.html">10 应该如何理解请求方法?.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/11 你能写出正确的网址吗?.md.html">11 你能写出正确的网址吗?.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/12 响应状态码该怎么用?.md.html">12 响应状态码该怎么用?.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/13 HTTP有哪些特点.md.html">13 HTTP有哪些特点.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/14 HTTP有哪些优点又有哪些缺点.md.html">14 HTTP有哪些优点又有哪些缺点.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/15 海纳百川HTTP的实体数据.md.html">15 海纳百川HTTP的实体数据.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/16 把大象装进冰箱HTTP传输大文件的方法.md.html">16 把大象装进冰箱HTTP传输大文件的方法.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/17 排队也要讲效率HTTP的连接管理.md.html">17 排队也要讲效率HTTP的连接管理.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/18 四通八达HTTP的重定向和跳转.md.html">18 四通八达HTTP的重定向和跳转.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/19 让我知道你是谁HTTP的Cookie机制.md.html">19 让我知道你是谁HTTP的Cookie机制.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/20 生鲜速递HTTP的缓存控制.md.html">20 生鲜速递HTTP的缓存控制.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/21 良心中间商HTTP的代理服务.md.html">21 良心中间商HTTP的代理服务.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/22 冷链周转HTTP的缓存代理.md.html">22 冷链周转HTTP的缓存代理.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/23 HTTPS是什么SSLTLS又是什么.md.html">23 HTTPS是什么SSLTLS又是什么.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/24 固若金汤的根本(上):对称加密与非对称加密.md.html">24 固若金汤的根本(上):对称加密与非对称加密.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/25 固若金汤的根本(下):数字签名与证书.md.html">25 固若金汤的根本(下):数字签名与证书.md.html</a>
</li>
<li>
<a class="current-tab" href="/专栏/透视HTTP协议/26 信任始于握手TLS1.2连接过程解析.md.html">26 信任始于握手TLS1.2连接过程解析.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/27 更好更快的握手TLS1.3特性解析.md.html">27 更好更快的握手TLS1.3特性解析.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/28 连接太慢该怎么办HTTPS的优化.md.html">28 连接太慢该怎么办HTTPS的优化.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/29 我应该迁移到HTTPS吗.md.html">29 我应该迁移到HTTPS吗.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/30 时代之风HTTP2特性概览.md.html">30 时代之风HTTP2特性概览.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/31 时代之风HTTP2内核剖析.md.html">31 时代之风HTTP2内核剖析.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/32 未来之路HTTP3展望.md.html">32 未来之路HTTP3展望.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/33 我应该迁移到HTTP2吗.md.html">33 我应该迁移到HTTP2吗.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/34 Nginx高性能的Web服务器.md.html">34 Nginx高性能的Web服务器.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/35 OpenResty更灵活的Web服务器.md.html">35 OpenResty更灵活的Web服务器.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/36 WAF保护我们的网络服务.md.html">36 WAF保护我们的网络服务.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/37 CDN加速我们的网络服务.md.html">37 CDN加速我们的网络服务.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/38 WebSocket沙盒里的TCP.md.html">38 WebSocket沙盒里的TCP.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/39 HTTP性能优化面面观.md.html">39 HTTP性能优化面面观.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/40 HTTP性能优化面面观.md.html">40 HTTP性能优化面面观.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/结束语 做兴趣使然的Hero.md.html">结束语 做兴趣使然的Hero.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>26 信任始于握手TLS1.2连接过程解析</h1>
<p>经过前几讲的介绍,你应该已经熟悉了对称加密与非对称加密、数字签名与证书等密码学知识。</p>
<p>有了这些知识“打底”,现在我们就可以正式开始研究 HTTPS 和 TLS 协议了。</p>
<h2>HTTPS 建立连接</h2>
<p>当你在浏览器地址栏里键入“<strong>https</strong>”开头的 URI再按下回车会发生什么呢</p>
<p>回忆一下[第 8 讲]的内容,你应该知道,浏览器首先要从 URI 里提取出协议名和域名。因为协议名是“https”所以浏览器就知道了端口号是默认的 443它再用 DNS 解析域名,得到目标的 IP 地址,然后就可以使用三次握手与网站建立 TCP 连接了。</p>
<p>在 HTTP 协议里,建立连接后,浏览器会立即发送请求报文。但现在是 HTTPS 协议,它需要再用另外一个“握手”过程,在 TCP 上建立安全连接,之后才是收发 HTTP 报文。</p>
<p>这个“握手”过程与 TCP 有些类似,是 HTTPS 和 TLS 协议里最重要、最核心的部分,懂了它,你就可以自豪地说自己“掌握了 HTTPS”。</p>
<h2>TLS 协议的组成</h2>
<p>在讲 TLS 握手之前,我先简单介绍一下 TLS 协议的组成。</p>
<p>TLS 包含几个子协议,你也可以理解为它是由几个不同职责的模块组成,比较常用的有记录协议、警报协议、握手协议、变更密码规范协议等。</p>
<p><strong>记录协议</strong>Record Protocol规定了 TLS 收发数据的基本单位记录record。它有点像是 TCP 里的 segment所有的其他子协议都需要通过记录协议发出。但多个记录数据可以在一个 TCP 包里一次性发出,也并不需要像 TCP 那样返回 ACK。</p>
<p><strong>警报协议</strong>Alert Protocol的职责是向对方发出警报信息有点像是 HTTP 协议里的状态码。比如protocol_version 就是不支持旧版本bad_certificate 就是证书有问题,收到警报后另一方可以选择继续,也可以立即终止连接。</p>
<p><strong>握手协议</strong>Handshake Protocol是 TLS 里最复杂的子协议,要比 TCP 的 SYN/ACK 复杂的多,浏览器和服务器会在握手过程中协商 TLS 版本号、随机数、密码套件等信息,然后交换证书和密钥参数,最终双方协商得到会话密钥,用于后续的混合加密系统。</p>
<p>最后一个是<strong>变更密码规范协议</strong>Change Cipher Spec Protocol它非常简单就是一个“通知”告诉对方后续的数据都将使用加密保护。那么反过来在它之前数据都是明文的。</p>
<p>下面的这张图简要地描述了 TLS 的握手过程,其中每一个“框”都是一个记录,多个记录组合成一个 TCP 包发送。所以最多经过两次消息往返4 个消息)就可以完成握手,然后就可以在安全的通信环境里发送 HTTP 报文,实现 HTTPS 协议。</p>
<p><img src="assets/69493b53f1b1d540acf886ebf021a26c.png" alt="img" /></p>
<h2>抓包的准备工作</h2>
<p>这次我们在实验环境里测试 TLS 握手的 URI 是“/26-1”看了上面的图你就可以知道TLS 握手的前几个消息都是明文的,能够在 Wireshark 里直接看。但只要出现了“Change Cipher Spec”后面的数据就都是密文了看到的也就会是乱码不知道究竟是什么东西。</p>
<p>为了更好地分析 TLS 握手过程,你可以再对系统和 Wireshark 做一下设置,让浏览器导出握手过程中的秘密信息,这样 Wireshark 就可以把密文解密,还原出明文。</p>
<p>首先,你需要在 Windows 的设置里新增一个系统变量“<strong>SSLKEYLOGFILE</strong>设置浏览器日志文件的路径比如“D:\http_study\www\temp\sslkey.log”具体的设置过程就不详细说了可以在设置里搜索“系统变量”</p>
<p><img src="assets/70b36338611d5a249a7d2fc448f06d42.png" alt="img" /></p>
<p>然后在 Wireshark 里设置“Protocols-TLS”较早版本的 Wireshark 里是“SSL”在“(Pre)-Master-Secret log filename”里填上刚才的日志文件。</p>
<p><img src="assets/0274e31e74e92b61892ec11cc3cd58e7.png" alt="img" /></p>
<p>设置好之后,过滤器选择“<strong>tcp port 443</strong>”,就可以抓到实验环境里的所有 HTTPS 数据了。</p>
<p>如果你觉得麻烦也没关系GitHub 上有抓好的包和相应的日志,用 Wireshark 直接打开就行。</p>
<h2>ECDHE 握手过程</h2>
<p>刚才你看到的是握手过程的简要图,我又画了一个详细图,对应 Wireshark 的抓包,下面我就用这个图来仔细剖析 TLS 的握手过程。</p>
<p><img src="assets/9caba6d4b527052bbe7168ed4013011e.png" alt="img" /></p>
<p>在 TCP 建立连接之后,浏览器会首先发一个“<strong>Client Hello</strong>”消息,也就是跟服务器“打招呼”。里面有客户端的版本号、支持的密码套件,还有一个<strong>随机数Client Random</strong>,用于后续生成会话密钥。</p>
<pre><code>Handshake Protocol: Client Hello
Version: TLS 1.2 (0x0303)
Random: 1cbf803321fd2623408dfe…
Cipher Suites (17 suites)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
</code></pre>
<p>这个的意思就是:“我这边有这些这些信息,你看看哪些是能用的,关键的随机数可得留着。”</p>
<p>作为“礼尚往来”服务器收到“Client Hello”后会返回一个“Server Hello”消息。把版本号对一下也给出一个<strong>随机数Server Random</strong>然后从客户端的列表里选一个作为本次通信使用的密码套件在这里它选择了“TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384”。</p>
<pre><code>Handshake Protocol: Server Hello
Version: TLS 1.2 (0x0303)
Random: 0e6320f21bae50842e96…
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
</code></pre>
<p>这个的意思就是:“版本号对上了,可以加密,你的密码套件挺多,我选一个最合适的吧,用椭圆曲线加 RSA、AES、SHA384。我也给你一个随机数你也得留着。”</p>
<p>然后服务器为了证明自己的身份就把证书也发给了客户端Server Certificate</p>
<p>接下来是一个关键的操作,因为服务器选择了 ECDHE 算法,所以它会在证书后发送“<strong>Server Key Exchange</strong>”消息,里面是<strong>椭圆曲线的公钥Server Params</strong>,用来实现密钥交换算法,再加上自己的私钥签名认证。</p>
<pre><code>Handshake Protocol: Server Key Exchange
EC Diffie-Hellman Server Params
Curve Type: named_curve (0x03)
Named Curve: x25519 (0x001d)
Pubkey: 3b39deaf00217894e...
Signature Algorithm: rsa_pkcs1_sha512 (0x0601)
Signature: 37141adac38ea4...
</code></pre>
<p>这相当于说:“刚才我选的密码套件有点复杂,所以再给你个算法的参数,和刚才的随机数一样有用,别丢了。为了防止别人冒充,我又盖了个章。”</p>
<p>之后是“<strong>Server Hello Done</strong>”消息,服务器说:“我的信息就是这些,打招呼完毕。”</p>
<p>这样第一个消息往返就结束了(两个 TCP 包),结果是客户端和服务器通过明文共享了三个信息:<strong>Client Random、Server Random 和 Server Params</strong></p>
<p>客户端这时也拿到了服务器的证书,那这个证书是不是真实有效的呢?</p>
<p>这就要用到第 25 讲里的知识了,开始走证书链逐级验证,确认证书的真实性,再用证书公钥验证签名,就确认了服务器的身份:“刚才跟我打招呼的不是骗子,可以接着往下走。”</p>
<p>然后,客户端按照密码套件的要求,也生成一个<strong>椭圆曲线的公钥Client Params</strong>,用“<strong>Client Key Exchange</strong>”消息发给服务器。</p>
<pre><code>Handshake Protocol: Client Key Exchange
EC Diffie-Hellman Client Params
Pubkey: 8c674d0e08dc27b5eaa…
</code></pre>
<p>现在客户端和服务器手里都拿到了密钥交换算法的两个参数Client Params、Server Params就用 ECDHE 算法一阵算,算出了一个新的东西,叫“<strong>Pre-Master</strong>”,其实也是一个随机数。</p>
<p>至于具体的计算原理和过程,因为太复杂就不细说了,但算法可以保证即使黑客截获了之前的参数,也是绝对算不出这个随机数的。</p>
<p>现在客户端和服务器手里有了三个随机数:<strong>Client Random、Server Random 和 Pre-Master</strong>。用这三个作为原始材料,就可以生成用于加密会 话的主密钥,叫“<strong>Master Secret</strong>”。而黑客因为拿不到“Pre-Master”所以也就得不到主密钥。</p>
<p>为什么非得这么麻烦,非要三个随机数呢?</p>
<p>这就必须说 TLS 的设计者考虑得非常周到了,他们不信任客户端或服务器伪随机数的可靠性,为了保证真正的“完全随机”“不可预测”,把三个不可靠的随机数混合起来,那么“随机”的程度就非常高了,足够让黑客难以猜测。</p>
<p>你一定很想知道“Master Secret”究竟是怎么算出来的吧贴一下 RFC 里的公式:</p>
<pre><code>master_secret = PRF(pre_master_secret, &quot;master secret&quot;,
ClientHello.random + ServerHello.random)
</code></pre>
<p>这里的“PRF”就是伪随机数函数它基于密码套件里的最后一个参数比如这次的 SHA384通过摘要算法来再一次强化“Master Secret”的随机性。</p>
<p>主密钥有 48 字节,但它也不是最终用于通信的会话密钥,还会再用 PRF 扩展出更多的密钥比如客户端发送用的会话密钥client_write_key、服务器发送用的会话密钥server_write_key等等避免只用一个密钥带来的安全隐患。</p>
<p>有了主密钥和派生的会话密钥,握手就快结束了。客户端发一个“<strong>Change Cipher Spec</strong>”,然后再发一个“<strong>Finished</strong>”消息,把之前所有发送的数据做个摘要,再加密一下,让服务器做个验证。</p>
<p>意思就是告诉服务器:“后面都改用对称算法加密通信了啊,用的就是打招呼时说的 AES加密对不对还得你测一下。”</p>
<p>服务器也是同样的操作,发“<strong>Change Cipher Spec</strong>”和“<strong>Finished</strong>”消息,双方都验证加密解密 OK握手正式结束后面就收发被加密的 HTTP 请求和响应了。</p>
<h2>RSA 握手过程</h2>
<p>整个握手过程可真是够复杂的,但你可能会问了,好像这个过程和其他地方看到的不一样呢?</p>
<p>刚才说的其实是如今主流的 TLS 握手过程,这与传统的握手有两点不同。</p>
<p>第一个,使用 ECDHE 实现密钥交换,而不是 RSA所以会在服务器端发出“Server Key Exchange”消息。</p>
<p>第二个,因为使用了 ECDHE客户端可以不用等到服务器发回“Finished”确认握手完毕立即就发出 HTTP 报文,省去了一个消息往返的时间浪费。这个叫“<strong>TLS False Start</strong>意思就是“抢跑”和“TCP Fast Open”有点像都是不等连接完全建立就提前发应用数据提高传输的效率。</p>
<p>实验环境在 440 端口(<a href="https://www.chrono.com:440/26-1">https://www.chrono.com:440/26-1</a>)实现了传统的 RSA 密钥交换没有“False Start”你可以课后自己抓包看一下这里我也画了个图。</p>
<p><img src="assets/cb9a89055eadb452b7835ba8db7c3ad2.png" alt="img" /></p>
<p>大体的流程没有变只是“Pre-Master”不再需要用算法生成而是客户端直接生成随机数然后用服务器的公钥加密通过“<strong>Client Key Exchange</strong>”消息发给服务器。服务器再用私钥解密,这样双方也实现了共享三个随机数,就可以生成主密钥。</p>
<h2>双向认证</h2>
<p>到这里 TLS 握手就基本讲完了。</p>
<p>不过上面说的是“<strong>单向认证</strong>”握手过程,只认证了服务器的身份,而没有认证客户端的身份。这是因为通常单向认证通过后已经建立了安全通信,用账号、密码等简单的手段就能够确认用户的真实身份。</p>
<p>但为了防止账号、密码被盗,有的时候(比如网上银行)还会使用 U 盾给用户颁发客户端证书,实现“<strong>双向认证</strong>”,这样会更加安全。</p>
<p>双向认证的流程也没有太多变化,只是在“<strong>Server Hello Done</strong>”之后,“<strong>Client Key Exchange</strong>”之前,客户端要发送“<strong>Client Certificate</strong>”消息,服务器收到后也把证书链走一遍,验证客户端的身份。</p>
<h2>小结</h2>
<p>今天我们学习了 HTTPS/TLS 的握手,内容比较多、比较难,不过记住下面四点就可以。</p>
<ol>
<li>HTTPS 协议会先与服务器执行 TCP 握手,然后执行 TLS 握手,才能建立安全连接;</li>
<li>握手的目标是安全地交换对称密钥需要三个随机数第三个随机数“Pre-Master”必须加密传输绝对不能让黑客破解</li>
<li>“Hello”消息交换随机数“Key Exchange”消息交换“Pre-Master”</li>
<li>“Change Cipher Spec”之前传输的都是明文之后都是对称密钥加密的密文。</li>
</ol>
<h2>课下作业</h2>
<ol>
<li>密码套件里的那些算法分别在握手过程中起了什么作用?</li>
<li>你能完整地描述一下 RSA 的握手过程吗?</li>
<li>你能画出双向认证的流程图吗?</li>
</ol>
<p>欢迎你把自己的学习体会写在留言区,与我和其他同学一起讨论。如果你觉得有所收获,也欢迎把文章分享给你的朋友。</p>
<p><img src="assets/93d002084d9bf8283bab3e34e3f4bf14.png" alt="unpreview" /></p>
</div>
</div>
<div>
<div style="float: left">
<a href="/专栏/透视HTTP协议/25 固若金汤的根本(下):数字签名与证书.md.html">上一页</a>
</div>
<div style="float: right">
<a href="/专栏/透视HTTP协议/27 更好更快的握手TLS1.3特性解析.md.html">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70997d198a6e3cfa","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>