<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>TLS | 酷 壳 - CoolShell</title>
	<atom:link href="https://coolshell.cn/tag/tls/feed" rel="self" type="application/rss+xml" />
	<link>https://coolshell.cn</link>
	<description>享受编程和技术所带来的快乐 - Coding Your Ambition</description>
	<lastBuildDate>Sat, 12 Feb 2022 05:10:15 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.2</generator>
	<item>
		<title>网络数字身份认证术</title>
		<link>https://coolshell.cn/articles/21708.html</link>
					<comments>https://coolshell.cn/articles/21708.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Sun, 02 Jan 2022 08:38:13 +0000</pubDate>
				<category><![CDATA[程序设计]]></category>
		<category><![CDATA[网络安全]]></category>
		<category><![CDATA[mTLS]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[TLS]]></category>
		<category><![CDATA[安全]]></category>
		<guid isPermaLink="false">https://coolshell.cn/?p=21708</guid>

					<description><![CDATA[<p>这篇文章是《HTTP API 认证授权术》的姊妹篇，在那篇文章中，主要介绍了 HTTP API 认证和授权技术中用到的 HTTP Basic, Digest A...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/21708.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/21708.html">网络数字身份认证术</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script><img decoding="async" loading="lazy" class="alignright size-medium wp-image-21716" src="https://coolshell.cn/wp-content/uploads/2022/01/iStock-1175502114-300x201.png" alt="" width="300" height="201" srcset="https://coolshell.cn/wp-content/uploads/2022/01/iStock-1175502114-300x201.png 300w, https://coolshell.cn/wp-content/uploads/2022/01/iStock-1175502114-768x514.png 768w, https://coolshell.cn/wp-content/uploads/2022/01/iStock-1175502114-404x270.png 404w, https://coolshell.cn/wp-content/uploads/2022/01/iStock-1175502114.png 800w" sizes="(max-width: 300px) 100vw, 300px" />这篇文章是《<a title="HTTP API 认证授权术" href="https://coolshell.cn/articles/19395.html" target="_blank" rel="noopener">HTTP API 认证授权术</a>》的姊妹篇，在那篇文章中，主要介绍了 HTTP API 认证和授权技术中用到的 HTTP Basic, Digest Access, HMAC, OAuth, JWT 等各种方式，主要是 API 上用到的一些技术，这篇文章主要想说的是另一个话题——身份认证。也就是说，怎么确认这个数据就是这个人发出来的？</p>
<h4>用户密码</h4>
<p>要解决这个问题，我们先来看一个最简单的解——使用密码，通常来说，在网络上要证明一个人的身份的话，都需要这个人的一些私密而唯一的东西。比如，像密码这样的东西，很多地方，只要你提供了你的用户名+密码，就可以确定这个人是你（注明：关于密码管理，强密码设定，密码泄漏，密码破解以及密码哄骗不在这篇文章的话题中），也就是说，这个密码是非常私密的事，我们可以假设，这个事全世界只能有当事人一个人知道，所以，当事人得供正确的密码，我们就可以认证这个人了。</p>
<p>为了加强密码的安全程度，一般会使用 2FA（Two-factor authentication）或 MFA（Multi-factor authentication），双因认证或多因认证，这需要用户提供一个唯一的可信设备，比如用户的手机，然后通过验证手机短信，或是像 <a href="https://en.wikipedia.org/wiki/Google_Authenticator" target="_blank" rel="noopener">Google Authenticator</a>  这样的动态口令来完成。这样的安全级别已经算是比较高了。如果能够再加上经常性的变更密码，那么安全级别就更好了。</p>
<p><span id="more-21708"></span></p>
<p>另外，一些公司还使用了生物密码来进行用户的身份验证，比如人脸识别。但是，我个人觉得人脸识别或是生物识别是比较糟糕的方式，因为：</p>
<ul>
<li>目前能被验证的生物信息（如人脸和指纹）太容易被别人获得和伪造了。</li>
<li>这样东西不能被变更和吊销，密码可以被吊销和重置，人脸则不能。</li>
</ul>
<h4>密钥对和证书</h4>
<p>密码可以解决身证认证的问题有很多问题，最重要的一个问题就是，你要把你的密码提供给对方，对方才能验证你的身份。你不可能把你的密码提供给全世界的人吧，这样的话，全世界的人都有你的密码了，那么任何人都能变成你了。所以，用户密码这个事只能存在于权威机构和普通用户之间，不能存在于普遍应用中。所以，这里需要使用更好的解决方案。</p>
<p>使用 ECC（<a title="Elliptic-Curve Cryptography" href="https://en.wikipedia.org/wiki/Elliptic-curve_cryptography" target="_blank" rel="noopener">Elliptic-Curve Cryptography</a>）椭圆曲线密码术，可以通过一个“密钥对”进行非对称加密。这种技术，在对信息进行加密和解密时，使用两个不同的密钥，其中一个用来做加密，另一个做解密。这样一来，我们就可以把其中一个密钥公布出去，称之为公钥，另一个密钥私密地保管好，称之为私钥。</p>
<p>比如，我用我的私钥加密信息，然后，我把这个私钥所配对的公钥发布给所有人，大家都用公钥解密信息，不用我的公钥你解密不了这个信息。这样一来，就可以保证这个信息是我发出来的，不但保证了信息安全，还完成了身份认证。</p>
<p><img decoding="async" loading="lazy" class="aligncenter size-large wp-image-21710" src="https://coolshell.cn/wp-content/uploads/2022/01/key.pair_-1024x390.png" alt="" width="640" height="244" srcset="https://coolshell.cn/wp-content/uploads/2022/01/key.pair_-1024x390.png 1024w, https://coolshell.cn/wp-content/uploads/2022/01/key.pair_-300x114.png 300w, https://coolshell.cn/wp-content/uploads/2022/01/key.pair_-768x293.png 768w, https://coolshell.cn/wp-content/uploads/2022/01/key.pair_-604x230.png 604w, https://coolshell.cn/wp-content/uploads/2022/01/key.pair_.png 1304w" sizes="(max-width: 640px) 100vw, 640px" /></p>
<p>这样的现实案例一般用于网站，也就是用户得要知道我访问的这个网站是真实的，不是别人做的。因为 DNS 很容易被 hack，你连上一个不可信的网络，这个网络里的 DNS 把这个网站的 IP 地址解析成什么 就是什么了。但是有了这个加密的机制后，网站把自己的信息加密后连同公钥给到访问者，访问解密后就知道是不是这个网站了。</p>
<p>但是，这里还是会有一个很严重的问题，那就是中间人攻击。如下图所示：</p>
<p><img decoding="async" loading="lazy" class="aligncenter wp-image-21712 size-full" src="https://coolshell.cn/wp-content/uploads/2022/01/middle.man_-e1641105543137.png" alt="" width="600" height="252" /></p>
<p>中间人 Chad 把自己伪装成 Bob 向 Alice 要信息，然后，再伪装成 Alice 对 Bob 说，这就是 Alice 的公钥，于是 Bob 也无法验证是不是 Alice 的公钥，因为公钥里就是一堆乱七八糟的数据，我们完全不能分辨哪个公钥属于 Alice 的。试想，如果我们收到声称属于银行的密钥。我们怎么知道它确实属于你的银行？</p>
<p>这里的答案就是<strong>使用数字证书</strong>。证书跟我们的身份证非常类似，其需要一个可信机构来颁发和验证的。这个证书机构 CA（Certificate Authority）是一个是大家都相信的权威机构，他用他的人品保证（当然一般会被严格管理和审计），CA 机构同样使用这样的非对称加密的技术来完成颁发和验证的事。下图展示了这一过程。</p>
<p><img decoding="async" loading="lazy" class="aligncenter size-large wp-image-21713" src="https://coolshell.cn/wp-content/uploads/2022/01/certificate-1024x532.png" alt="" width="640" height="333" srcset="https://coolshell.cn/wp-content/uploads/2022/01/certificate-1024x532.png 1024w, https://coolshell.cn/wp-content/uploads/2022/01/certificate-300x156.png 300w, https://coolshell.cn/wp-content/uploads/2022/01/certificate-768x399.png 768w, https://coolshell.cn/wp-content/uploads/2022/01/certificate-519x270.png 519w, https://coolshell.cn/wp-content/uploads/2022/01/certificate.png 1362w" sizes="(max-width: 640px) 100vw, 640px" /></p>
<p>说明一下上面这个图：</p>
<ol>
<li>为了解决公钥认证的问题的，我们需要一个权威的CA 机构。</li>
<li>Alice 把自己的信息（姓名、组织，地址，电邮，网址等）和自己的公钥打包成一个 CSR 的文件，发给 CA 机构，</li>
<li>CA 机构会来找 Alice 做物理世界的认证，如果通过后，就会用自己的机构私钥，把CSR 变成一个签名证书。</li>
<li>Bob 同学拿到 Alice 的证书，用 CA 机构的公钥解密后，得到 Alice 的公钥</li>
<li>后面就可以签证 信息是否来自 Alice 了。</li>
</ol>
<p>是的，这个过程就是在“套娃”，这种证书机构还可以给下级的证书机构发证，于是就会一层套一层地，形成一个证书链，顶层的叫根证书，你得绝对信任之。对于验证证书真实性的客户端，它需要能够验证链中所有 CA 的签名，这意味着客户端需要访问链中所有 CA 的证书。</p>
<h4>证书生成过程演示</h4>
<p>并不是所有的场景都需要向这些大型的 CA 机构申请公钥证书，在任何一个企业，组织或是团体内都可以自己形这样的“小王国”，也就是说，你可以自行生成这样的证书，只需要你自己保证自己的生成证书的私钥的安全，以及不需要扩散到整个互联网。下面，我们用 <code>openssl</code>命令来演示这个过程。</p>
<p>1）生成 CA 的证书（公钥） <code>ca.crt</code> 和私钥 <code>ca.key</code></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">openssl req -newkey rsa:2048 \
    -new -nodes -x509 \
    -days 365 \
    -out ca.crt \
    -keyout ca.key \
    -subj "/C=SO/ST=Earth/L=Mountain/O=CoolShell/OU=HQ/CN=localhost"</pre>
<p>2)  生成 alice 的私钥</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">openssl genrsa -out alice.key 2048</pre>
<p>3）生成 Alice 的 CSR &#8211; Certificate Signing Request</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">openssl req -new -key alice.key 365 -out alice.csr \
    -subj "/C=CN/ST=Beijing/L=Haidian/O=CoolShell/OU=Test/CN=localhost.alice"</pre>
<p>4）使用 CA 给 Alice 签名证书</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">openssl x509  -req -in alice.csr \
    -extfile &lt;(printf "subjectAltName=DNS:localhost.alice") \ 
    -CA ca.crt -CAkey ca.key  \
    -days 365 -sha256 -CAcreateserial \
    -out alice.crt</pre>
<h4>双向认证 mTLS</h4>
<p>上面，我们说的基本上都是单向认证，大量的场景都是确保用户方访问的是真正的服务方，如：银行，电商网站，等。这样可以保证用户不会被钓鱼网站或是中间人攻击。但是，很多时候，我们也是需要双向认证的。下面是一个典型的场景——微信支付和商户间交互</p>
<ul>
<li>用户到商家那边买东西，商家要求用户进行支付。</li>
<li>用户选择了微信支付，于是，界面从商户侧切到了微信侧</li>
<li>微信那边支付完成后，商户这边收到微信那边支付完成的通知，于是开始发货。</li>
</ul>
<p>这个过程中有件事非常重要——就是微信通知商户支付完成的时候。</p>
<ul>
<li>微信得确保通知到的就是用户所支付商户，而不是别个。</li>
<li>商户也得要能确认，来通知我的就是微信，不是别人。</li>
</ul>
<p>一般来说，微信会给商户一个 AppID和一个 AppSerct，用这个来确保是我认证过的商户来调用我，然后，需要商户在自己的系统里填一个回调的 URL，并通过平台设置的 key来做 MD5/HMAC的签名来确保是官方的回调。这都是在《<a title="HTTP API 认证授权术" href="https://coolshell.cn/articles/19395.html" target="_blank" rel="noopener">HTTP API 认证授权术</a>》中提到过的技术，是相对传统的技术。</p>
<p>如今，<b>mTLS是</b>确保云原生应用程序中服务之间的通信安全的首选协议。 也就是双向认证。</p>
<p>传统的 TLS 认证过程是：</p>
<ol dir="auto">
<li>客户端连接到服务器</li>
<li>服务器提供其 TLS 证书</li>
<li>客户端验证服务器的证书</li>
<li>客户端和服务器通过加密的 TLS 连接交换信息</li>
</ol>
<p dir="auto">在 mTLS 中，客户端和服务器都有一个证书，双方都使用他们的公钥/私钥对进行身份验证。与常规 TLS 相比，mTLS 中有额外的步骤来验证双方（以<strong>粗体显示的</strong>额外步骤）：</p>
<ol dir="auto">
<li>客户端连接到服务器</li>
<li>服务器提供其 TLS 证书</li>
<li>客户端验证服务器的证书</li>
<li><strong>客户端出示其 TLS 证书</strong></li>
<li><strong>服务器验证客户端的证书</strong></li>
<li><strong>服务器授予访问权限</strong></li>
<li>客户端和服务器通过加密的 TLS 连接交换信息</li>
</ol>
<p>mTLS 需要“根”TLS 证书；这我们自己来完成证书颁发机构的职责。授权客户端和服务器使用的证书必须与此根证书相对应。根证书是自签名的，这意味着我们需要自己创建它。（注：此方法不适用于公共 Internet 上的单向 TLS，因为外部证书颁发机构必须颁发这些证书）</p>
<p>那么，为什么整个互联网上都用了 TLS 了，为什么 不升级一下使用 mTLS？这里有两方面的原因：</p>
<ul>
<li>公共互联网上要解决的问题是：A) 确保用户访问到的是正确的网站，而不是钓鱼网站。B）网站传输的内容是安全和私密且不会被篡改的。</li>
<li>将 TLS 证书分发到所有最终用户设备将非常困难。生成、管理和验证为此所需的数十亿个证书几乎是不可能的任务。</li>
</ul>
<p>在较小的范围内，mTLS 对于单个组织非常有用且非常实用，尤其是当这些组织采用零信任方法来确保网络安全时。由于默认情况下零信任方法不信任任何用户、设备或请求，因此组织必须能够在每次尝试访问网络中的任何点时对每个用户、设备和请求进行身份验证。mTLS 通过对用户进行身份验证和设备验证来帮助实现这一目标。</p>
<p>关于 mTLS，这里有一个我用 Golang 写的示例 &#8211; <a href="https://github.com/haoel/mTLS" target="_blank" rel="noopener">https://github.com/haoel/mTLS</a>，大家可以参考一下。</p>
<p>P.S. 本文图版中的卡司来自安全圈的标准 Cast，参看<a href="https://en.wikipedia.org/wiki/Alice_and_Bob" target="_blank" rel="noopener"> Alice and Bob</a>。</p>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" id="wp_rp_first"><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/19395.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2019/05/Authorization-360x200-1-150x150.png" alt="HTTP API 认证授权术" width="150" height="150" /></a><a href="https://coolshell.cn/articles/19395.html" class="wp_rp_title">HTTP API 认证授权术</a></li><li ><a href="https://coolshell.cn/articles/21003.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2020/06/time-bomb-150x150.png" alt="计时攻击 Timing Attacks" width="150" height="150" /></a><a href="https://coolshell.cn/articles/21003.html" class="wp_rp_title">计时攻击 Timing Attacks</a></li><li ><a href="https://coolshell.cn/articles/19840.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2019/10/HTTP-770x513-300x200-1-150x150.jpg" alt="HTTP的前世今生" width="150" height="150" /></a><a href="https://coolshell.cn/articles/19840.html" class="wp_rp_title">HTTP的前世今生</a></li><li ><a href="https://coolshell.cn/articles/18094.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2017/08/enable-https-banner-150x150.png" alt="如何免费的让网站启用HTTPS" width="150" height="150" /></a><a href="https://coolshell.cn/articles/18094.html" class="wp_rp_title">如何免费的让网站启用HTTPS</a></li><li ><a href="https://coolshell.cn/articles/17607.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2017/01/MongoDB-150x150.jpg" alt="从 MongoDB “赎金事件” 看安全问题" width="150" height="150" /></a><a href="https://coolshell.cn/articles/17607.html" class="wp_rp_title">从 MongoDB “赎金事件” 看安全问题</a></li><li ><a href="https://coolshell.cn/articles/17066.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2015/04/phishing-1-150x150.jpg" alt="关于移动端的钓鱼式攻击" width="150" height="150" /></a><a href="https://coolshell.cn/articles/17066.html" class="wp_rp_title">关于移动端的钓鱼式攻击</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/21708.html">网络数字身份认证术</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/21708.html/feed</wfw:commentRss>
			<slash:comments>14</slash:comments>
		
		
			</item>
		<item>
		<title>HTTP的前世今生</title>
		<link>https://coolshell.cn/articles/19840.html</link>
					<comments>https://coolshell.cn/articles/19840.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Tue, 01 Oct 2019 11:21:10 +0000</pubDate>
				<category><![CDATA[技术读物]]></category>
		<category><![CDATA[程序设计]]></category>
		<category><![CDATA[系统架构]]></category>
		<category><![CDATA[网络安全]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[QUIC]]></category>
		<category><![CDATA[TCP]]></category>
		<category><![CDATA[TLS]]></category>
		<category><![CDATA[UDP]]></category>
		<guid isPermaLink="false">https://coolshell.cn/?p=19840</guid>

					<description><![CDATA[<p>HTTP (Hypertext transfer protocol) 翻译成中文是超文本传输协议，是互联网上重要的一个协议，由欧洲核子研究委员会CERN的英国工...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/19840.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/19840.html">HTTP的前世今生</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script><img decoding="async" loading="lazy" class="alignright" src="https://coolshell.cn/wp-content/uploads/2019/10/HTTP-770x513-300x200.jpg" alt="" width="300" height="200" />HTTP (Hypertext transfer protocol) 翻译成中文是超文本传输协议，是互联网上重要的一个协议，由欧洲核子研究委员会CERN的英国工程师 <a title="" href="https://en.wikipedia.org/wiki/Tim_Berners-Lee">Tim Berners-Lee</a> v发明的，同时，他也是WWW的发明人，最初的主要是用于传递通过HTML封装过的数据。在1991年发布了HTTP 0.9版，在1996年发布1.0版，1997年是1.1版，1.1版也是到今天为止传输最广泛的版本（初始<a class="external text" href="https://tools.ietf.org/html/rfc2068" rel="nofollow">RFC 2068</a> 在1997年发布， 然后在1999年被 <a class="external text" href="https://tools.ietf.org/html/rfc2616" rel="nofollow">RFC 2616</a> 取代，再在2014年被 <a class="external text" href="https://tools.ietf.org/html/rfc7230" rel="nofollow">RFC 7230</a> /<a class="external text" href="https://tools.ietf.org/html/rfc7231" rel="nofollow">7231</a>/<a class="external text" href="https://tools.ietf.org/html/rfc7232" rel="nofollow">7232</a>/<a class="external text" href="https://tools.ietf.org/html/rfc7233" rel="nofollow">7233</a>/<a class="external text" href="https://tools.ietf.org/html/rfc7234" rel="nofollow">7234</a>/<a class="external text" href="https://tools.ietf.org/html/rfc7235" rel="nofollow">7235</a>取代），2015年发布了2.0版，其极大的优化了HTTP/1.1的性能和安全性，而2018年发布的3.0版，继续优化HTTP/2，激进地使用UDP取代TCP协议，目前，HTTP/3 在2019年9月26日 被 Chrome，Firefox，和Cloudflare支持，所以我想写下这篇文章，简单地说一下HTTP的前世今生，让大家学到一些知识，并希望可以在推动一下HTTP标准协议的发展。</p>
<h4>HTTP 0.9 / 1.0</h4>
<p>0.9和1.0这两个版本，就是最传统的 request &#8211; response的模式了，HTTP 0.9版本的协议简单到极点，请求时，不支持请求头，只支持 <code>GET</code> 方法，没了。HTTP 1.0 扩展了0.9版，其中主要增加了几个变化：</p>
<p><span id="more-19840"></span></p>
<ul>
<li>在请求中加入了HTTP版本号，如：<code>GET /coolshell/index.html HTTP/1.0</code></li>
<li>HTTP 开始有 header了，不管是request还是response 都有header了。</li>
<li>增加了HTTP Status Code 标识相关的状态码。</li>
<li>还有 <code>Content-Type</code> 可以传输其它的文件了。</li>
</ul>
<p>我们可以看到，HTTP 1.0 开始让这个协议变得很文明了，一种工程文明。因为：</p>
<ul>
<li>一个协议有没有版本管理，是一个工程化的象征。</li>
<li>header是协议可以说是把元数据和业务数据解耦，也可以说是控制逻辑和业务逻辑的分离。</li>
<li>Status Code 的出现可以让请求双方以及第三方的监控或管理程序有了统一的认识。最关键是还是控制错误和业务错误的分离。</li>
</ul>
<p>（注：国内很多公司HTTP无论对错只返回200，这种把HTTP Status Code 全部抹掉完全是一种工程界的倒退）</p>
<p>但是，HTTP1.0性能上有一个很大的问题，那就是每请求一个资源都要新建一个TCP链接，而且是串行请求，所以，就算网络变快了，打开网页的速度也还是很慢。所以，HTTP 1.0 应该是一个必需要淘汰的协议了。</p>
<h4> HTTP/1.1</h4>
<p>HTTP/1.1 主要解决了HTTP 1.0的网络性能的问题，以及增加了一些新的东西：</p>
<ul>
<li>可以设置 <code>keepalive</code> 来让HTTP重用TCP链接，重用TCP链接可以省了每次请求都要在广域网上进行的TCP的三次握手的巨大开销。这是所谓的“<strong>HTTP 长链接</strong>” 或是 “<strong>请求响应式的HTTP 持久链接</strong>”。英文叫 HTTP Persistent connection.</li>
<li>然后支持pipeline网络传输，只要第一个请求发出去了，不必等其回来，就可以发第二个请求出去，可以减少整体的响应时间。（注：非幂等的POST 方法或是有依赖的请求是不能被pipeline化的）</li>
<li>支持 Chunked Responses ，也就是说，在Response的时候，不必说明 <code>Content-Length</code> 这样，客户端就不能断连接，直到收到服务端的EOF标识。这种技术又叫 “<strong>服务端Push模型</strong>”，或是 “<strong>服务端Push式的HTTP 持久链接</strong>”</li>
<li>还增加了 cache control 机制。</li>
<li>协议头注增加了 Language, Encoding, Type 等等头，让客户端可以跟服务器端进行更多的协商。</li>
<li>还正式加入了一个很重要的头—— <code><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Host" target="_blank" rel="noopener noreferrer">HOST</a></code>这样的话，服务器就知道你要请求哪个网站了。因为可以有多个域名解析到同一个IP上，要区分用户是请求的哪个域名，就需要在HTTP的协议中加入域名的信息，而不是被DNS转换过的IP信息。</li>
<li>正式加入了 <code>OPTIONS</code> 方法，其主要用于 <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" target="_blank" rel="noopener noreferrer">CORS &#8211; Cross Origin Resource Sharing</a> 应用。</li>
</ul>
<p>HTTP/1.1应该分成两个时代，一个是2014年前，一个是2014年后，因为2014年HTTP/1.1有了一组RFC（<a class="external text" href="https://tools.ietf.org/html/rfc7230" rel="nofollow">7230</a> /<a class="external text" href="https://tools.ietf.org/html/rfc7231" rel="nofollow">7231</a>/<a class="external text" href="https://tools.ietf.org/html/rfc7232" rel="nofollow">7232</a>/<a class="external text" href="https://tools.ietf.org/html/rfc7233" rel="nofollow">7233</a>/<a class="external text" href="https://tools.ietf.org/html/rfc7234" rel="nofollow">7234</a>/<a class="external text" href="https://tools.ietf.org/html/rfc7235" rel="nofollow">7235</a>），这组RFC又叫“HTTP/2 预览版”。其中影响HTTP发展的是两个大的需求：</p>
<ul>
<li>一个需要是加大了HTTP的安全性，这样就可以让HTTP应用得广泛，比如，使用TLS协议。</li>
<li>另一个是让HTTP可以支持更多的应用，在HTTP/1.1 下，HTTP已经支持四种网络协议：
<ul>
<li>传统的短链接。</li>
<li>可重用TCP的的长链接模型。</li>
<li>服务端push的模型。</li>
<li>WebSocket模型。</li>
</ul>
</li>
</ul>
<p>自从2005年以来，整个世界的应用API越来多，这些都造就了整个世界在推动HTTP的前进，我们可以看到，<strong>自2014的HTTP/1.1 以来，这个世界基本的应用协议的标准基本上都是向HTTP看齐了，也许2014年前，还有一些专用的RPC协议，但是2014年以后，HTTP协议的增强，让我们实在找不出什么理由不向标准靠拢，还要重新发明轮子了。</strong></p>
<h4>HTTP/2</h4>
<p>虽然 HTTP/1.1 已经开始变成应用层通讯协议的一等公民了，但是还是有性能问题，虽然HTTP/1.1 可以重用TCP链接，但是请求还是一个一个串行发的，需要保证其顺序。然而，大量的网页请求中都是些资源类的东西，这些东西占了整个HTTP请求中最多的传输数据量。所以，理论上来说，如果能够并行这些请求，那就会增加更大的网络吞吐和性能。</p>
<p>另外，HTTP/1.1传输数据时，是以文本的方式，借助耗CPU的zip压缩的方式减少网络带宽，但是耗了前端和后端的CPU。这也是为什么很多RPC协议诟病HTTP的一个原因，就是数据传输的成本比较大。</p>
<p>其实，在2010年时，Google 就在搞一个实验型的协议，这个协议叫<a href="https://en.wikipedia.org/wiki/SPDY">SPDY</a>，这个协议成为了HTTP/2的基础（也可以说成HTTP/2就是SPDY的复刻）。HTTP/2基本上解决了之前的这些性能问题，其和HTTP/1.1最主要的不同是：</p>
<ul>
<li>HTTP/2是一个二进制协议，增加了数据传输的效率。</li>
<li>HTTP/2是可以在一个TCP链接中并发请求多个HTTP请求，移除了HTTP/1.1中的串行请求。</li>
<li>HTTP/2会压缩头，如果你同时发出多个请求，他们的头是一样的或是相似的，那么，协议会帮你消除重复的部分。这就是所谓的HPACK算法（参看<a class="external mw-magiclink-rfc" href="https://tools.ietf.org/html/rfc7541" target="_blank" rel="nofollow noopener noreferrer">RFC 7541</a> 附录A）</li>
<li>HTTP/2允许服务端在客户端放cache，又叫服务端push，也就是说，你没有请求的东西，我服务端可以先送给你放在你的本地缓存中。比如，你请求X，我服务端知道X依赖于Y，虽然你没有的请求Y，但我把把Y跟着X的请求一起返回客户端。</li>
</ul>
<p>对于这些性能上的改善，在Medium上有篇文章你可看一下相关的细节说明和测试“<a href="https://medium.com/@factoryhr/http-2-the-difference-between-http-1-1-benefits-and-how-to-use-it-38094fa0e95b" target="_blank" rel="noopener noreferrer">HTTP/2: the difference between HTTP/1.1, benefits and how to use it</a>”</p>
<p>当然，还需要注意到的是HTTP/2的协议复杂度比之前所有的HTTP协议的复杂度都上升了许多许多，其内部还有很多看不见的东西，比如其需要维护一个“优先级树”来用于来做一些资源和请求的调度和控制。如此复杂的协议，自然会产生一些不同的声音，或是降低协议的可维护和可扩展性。所以也有一些争议。尽管如此，HTTP/2还是很快地被世界所采用。</p>
<p>HTTP/2 是2015年推出的，其发布后，Google 宣布移除对SPDY的支持，拥抱标准的 HTTP/2。过了一年后，就有8.7%的网站开启了HTTP/2，根据 <a href="https://w3techs.com/technologies/details/ce-http2/all/all" target="_blank" rel="noopener noreferrer">这份报告</a> ，截止至本文发布时（2019年10月1日 ）， 在全世界范围内已经有41%的网站开启了HTTP/2。</p>
<p>HTTP/2的官方组织在 Github 上维护了一份<a href="https://github.com/http2/http2-spec/wiki/Implementations" target="_blank" rel="noopener noreferrer">各种语言对HTTP/2的实现列表</a>，大家可以去看看。</p>
<p>我们可以看到，HTTP/2 在性能上对HTTP有质的提高，所以，HTTP/2 被采用的也很快，所以，<strong>如果你在你的公司内负责架构的话，HTTP/2是你一个非常重要的需要推动的一个事，除了因为性能上的问题，推动标准落地也是架构师的主要职责，因为，你企业内部的架构越标准，你可以使用到开源软件，或是开发方式就会越有效率，跟随着工业界的标准的发展，你的企业会非常自然的享受到标准所带来的红利。</strong></p>
<h4>HTTP/3</h4>
<p>然而，这个世界没有完美的解决方案，HTTP/2也不例外，其主要的问题是：若干个HTTP的请求在复用一个TCP的连接，底层的TCP协议是不知道上层有多少个HTTP的请求的，所以，一旦发生丢包，造成的问题就是所有的HTTP请求都必需等待这个丢了的包被重传回来，哪怕丢的那个包不是我这个HTTP请求的。因为TCP底层是没有这个知识了。</p>
<p>这个问题又叫<a href="https://en.wikipedia.org/wiki/Head-of-line_blocking" target="_blank" rel="noopener noreferrer">Head-of-Line Blocking</a>问题，这也是一个比较经典的流量调度的问题。这个问题最早主要的发生的交换机上。下图来自Wikipedia。</p>
<p><img decoding="async" loading="lazy" class="aligncenter" src="https://coolshell.cn/wp-content/uploads/2019/10/HOL_blocking.png" alt="" width="423" height="220" /></p>
<p>图中，左边的是输入队列，其中的1，2，3，4表示四个队列，四个队列中的1，2，3，4要去的右边的output的端口号。此时，第一个队列和第三个队列都要写右边的第四个端口，然后，一个时刻只能处理一个包，所以，一个队列只能在那等另一个队列写完后。然后，其此时的3号或1号端口是空闲的，而队列中的要去1和3号端号的数据，被第四号端口给block住了。这就是所谓的HOL blocking问题。</p>
<p>HTTP/1.1中的pipeline中如果有一个请求block了，那么队列后请求也统统被block住了；HTTP/2 多请求复用一个TCP连接，一旦发生丢包，就会block住所有的HTTP请求。这样的问题很讨厌。好像基本无解了。</p>
<p>是的TCP是无解了，但是UDP是有解的 ！<strong>于是HTTP/3破天荒地把HTTP底层的TCP协议改成了UDP！</strong></p>
<p>然后又是Google 家的协议进入了标准 &#8211; QUIC （Quick UDP Internet Connections）。接下来是QUIC协议的几个重要的特性，为了讲清楚这些特性，我需要带着问题来讲（注：下面的网络知识，如果你看不懂的话，你需要学习一下《<a href="https://book.douban.com/subject/1088054/" target="_blank" rel="noopener noreferrer">TCP/IP详解</a>》一书（在我写blog的这15年里，这本书推荐了无数次了），或是看一下本站的《<a href="https://coolshell.cn/articles/11564.html">TCP的那些事</a>》。）：</p>
<ul>
<li>首先是上面的Head-of-Line blocking问题，在UDP的世界中，这个就没了。这个应该比较好理解，因为UDP不管顺序，不管丢包（当然，QUIC的一个任务是要像TCP的一个稳定，所以QUIC有自己的丢包重传的机制）</li>
<li>TCP是一个无私的协议，也就是说，如果网络上出现拥塞，大家都会丢包，于是大家都会进入拥塞控制的算法中，这个算法会让所有人都“冷静”下来，然后进入一个“慢启动”的过程，包括在TCP连接建立时，这个慢启动也在，所以导致TCP性能迸发地比较慢。QUIC基于UDP，使用更为激进的方式。同时，QUIC有一套自己的丢包重传和拥塞控制的协，一开始QUIC是重新实现一TCP 的 CUBIC算法，但是随着BBR算法的成熟（BBR也在借鉴CUBIC算法的数学模型），QUIC也可以使用BBR算法。这里，多说几句，<strong>从模型来说，以前的TCP的拥塞控制算法玩的是数学模型，而新型的TCP拥塞控制算法是以BBR为代表的测量模型</strong>，理论上来说，后者会更好，但QUIC的团队在一开始觉得BBR不如CUBIC的算法好，所以没有用。现在的BBR 2.x借鉴了CUBIC数学模型让拥塞控制更公平。这里有文章大家可以一读“<a href="https://medium.com/google-cloud/tcp-bbr-magic-dust-for-network-performance-57a5f1ccf437" target="_blank" rel="noopener noreferrer">TCP BBR : Magic dust for network performance.</a>”</li>
<li>接下来，现在要建立一个HTTPS的连接，先是TCP的三次握手，然后是TLS的三次握手，要整出六次网络交互，一个链接才建好，虽说HTTP/1.1和HTTP/2的连接复用解决这个问题，但是基于UDP后，UDP也得要实现这个事。于是QUIC直接把TCP的和TLS的合并成了三次握手（对此，在HTTP/2的时候，是否默认开启TLS业内是有争议的，反对派说，TLS在一些情况下是不需要的，比如企业内网的时候，而支持派则说，TLS的那些开销，什么也不算了）。</li>
</ul>
<table>
<tbody>
<tr>
<td><img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2019/10/http-request-over-tcp-tls@2x-292x300.png" alt="" width="292" height="300" /></td>
<td><img decoding="async" loading="lazy" class="" src="https://coolshell.cn/wp-content/uploads/2019/10/http-request-over-quic@2x-300x215.png" alt="" width="312" height="227" /></td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>所以，QUIC是一个在UDP之上的伪TCP +TLS +HTTP/2的多路复用的协议。</p>
<p>但是对于UDP还是有一些挑战的，这个挑战主要来自互联网上的各种网络设备，这些设备根本不知道是什么QUIC，他们看QUIC就只能看到的就是UDP，所以，在一些情况下，UDP就是有问题的，</p>
<ul>
<li>比如在NAT的环境下，如果是TCP的话，NAT路由或是代理服务器，可以通过记录TCP的四元组（源地址、源端口，目标地址，目标端口）来做连接映射的，然而，在UDP的情况下不行了。于是，QUIC引入了个叫connection id的不透明的ID来标识一个链接，用这种业务ID很爽的一个事是，如果你从你的3G/4G的网络切到WiFi网络（或是反过来），你的链接不会断，因为我们用的是connection id，而不是四元组。</li>
</ul>
<ul>
<li>然而就算引用了connection id，也还是会有问题 ，比如一些不够“聪明”的等价路由交换机，这些交换机会通过四元组来做hash把你的请求的IP转到后端的实际的服务器上，然而，他们不懂connection id，只懂四元组，这么导致属于同一个connection id但是四元组不同的网络包就转到了不同的服务器上，这就是导致数据不能传到同一台服务器上，数据不完整，链接只能断了。所以，你需要更聪明的算法（可以参看 Facebook 的 <a href="https://github.com/facebookincubator/katran" target="_blank" rel="noopener noreferrer">Katran</a> 开源项目 ）</li>
</ul>
<p>好了，就算搞定上面的东西，还有一些业务层的事没解，这个事就是 HTTP/2的头压缩算法 HPACK，HPACK需要维护一个动态的字典表来分析请求的头中哪些是重复的，HPACK的这个数据结构需要在encoder和decoder端同步这个东西。在TCP上，这种同步是透明的，然而在UDP上这个事不好干了。所以，这个事也必需要重新设计了，基于QUIC的QPACK就出来了，利用两个附加的QUIC steam，一个用来发送这个字典表的更新给对方，另一个用来ack对方发过来的update。</p>
<p>目前看下来，HTTP/3目前看上去没有太多的协议业务逻辑上的东西，更多是HTTP/2 + QUIC协议。但，HTTP/3 因为动到了底层协议，所以，在普及方面上可能会比 HTTP/2要慢的多的多。但是，可以看到QUIC协议的强大，细思及恐，QUIC这个协议真对TCP是个威胁，如果QUIC成熟了，TCP是不是会有可能成为历史呢？</p>
<p>未来十年，让我们看看UDP是否能够逆袭TCP……</p>
<p>(全文完)<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/7490.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/06/f1-150x150.jpg" alt="性能调优攻略" width="150" height="150" /></a><a href="https://coolshell.cn/articles/7490.html" class="wp_rp_title">性能调优攻略</a></li><li ><a href="https://coolshell.cn/articles/22263.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2022/07/wall_clock-300x167-1-150x150.jpeg" alt="从一次经历谈 TIME_WAIT 的那些事" width="150" height="150" /></a><a href="https://coolshell.cn/articles/22263.html" class="wp_rp_title">从一次经历谈 TIME_WAIT 的那些事</a></li><li ><a href="https://coolshell.cn/articles/22173.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2022/02/http_method-150x150.png" alt="“一把梭：REST API 全用 POST”" width="150" height="150" /></a><a href="https://coolshell.cn/articles/22173.html" class="wp_rp_title">“一把梭：REST API 全用 POST”</a></li><li ><a href="https://coolshell.cn/articles/21708.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2022/01/iStock-1175502114-150x150.png" alt="网络数字身份认证术" width="150" height="150" /></a><a href="https://coolshell.cn/articles/21708.html" class="wp_rp_title">网络数字身份认证术</a></li><li ><a href="https://coolshell.cn/articles/18094.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2017/08/enable-https-banner-150x150.png" alt="如何免费的让网站启用HTTPS" width="150" height="150" /></a><a href="https://coolshell.cn/articles/18094.html" class="wp_rp_title">如何免费的让网站启用HTTPS</a></li><li ><a href="https://coolshell.cn/articles/11609.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2014/05/xin_2001040422167711230318-150x150.jpg" alt="TCP 的那些事儿（下）" width="150" height="150" /></a><a href="https://coolshell.cn/articles/11609.html" class="wp_rp_title">TCP 的那些事儿（下）</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/19840.html">HTTP的前世今生</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/19840.html/feed</wfw:commentRss>
			<slash:comments>77</slash:comments>
		
		
			</item>
	</channel>
</rss>
