<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ HTTPS - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ freeCodeCamp 是一个免费学习编程的开发者社区，涵盖 Python、HTML、CSS、React、Vue、BootStrap、JSON 教程等，还有活跃的技术论坛和丰富的社区活动，在你学习编程和找工作时为你提供建议和帮助。 ]]>
        </description>
        <link>https://www.freecodecamp.org/chinese/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ HTTPS - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/chinese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Thu, 18 Jun 2026 10:44:44 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/chinese/news/tag/https/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ HTTP 和 HTTPS 的区别是什么 ]]>
                </title>
                <description>
                    <![CDATA[ 我们每天都和HTTP和HTTPS打交道，但是很多人都不知道这两者之间的区别是什么。 大多数计算机用户看到浏览器告知他们这个应用不安全，很有可能有黑客想要获取他们重要的信息的时候，用户可能跑得比博尔特还要快。 但这个安全风险是可以避免的，这就是为什么HTTPS引入并取代HTTP。今天我们就来讨论这个话题。 :) 我们将讨论：  1.  什么是HTTP  2.  HTTP如何工作  3.  HTTP的功能  4.  如何知道一个网站不安全  5.  所有的HTTP网站都不安全吗  6.  什么是HTTPS  7.  HTTPS如何工作  8.  HTTPS的功能  9.  加密的工作原理  10. 如何知道一个网站是安全的  11. SSL证书是什么  12. SSL是如何工作的 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/http-vs-https/</link>
                <guid isPermaLink="false">6303493460480505ded7ade3</guid>
                
                    <category>
                        <![CDATA[ HTTPS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTTP ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ PapayaHUANG ]]>
                </dc:creator>
                <pubDate>Mon, 22 Aug 2022 03:20:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2022/08/HTTP-VS-HTTPS.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>原文：</strong> <a href="https://www.freecodecamp.org/news/http-vs-https/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">HTTP vs HTTPS – What's the Difference?</a>
      </p><!--kg-card-begin: markdown--><p>我们每天都和HTTP和HTTPS打交道，但是很多人都不知道这两者之间的区别是什么。</p>
<p>大多数计算机用户看到浏览器告知他们这个应用不安全，很有可能有黑客想要获取他们重要的信息的时候，用户可能跑得比博尔特还要快。</p>
<p>但这个安全风险是可以避免的，这就是为什么HTTPS引入并取代HTTP。今天我们就来讨论这个话题。 :)</p>
<h2 id="">我们将讨论：</h2>
<ol>
<li>什么是HTTP</li>
<li>HTTP如何工作</li>
<li>HTTP的功能</li>
<li>如何知道一个网站不安全</li>
<li>所有的HTTP网站都不安全吗</li>
<li>什么是HTTPS</li>
<li>HTTPS如何工作</li>
<li>HTTPS的功能</li>
<li>加密的工作原理</li>
<li>如何知道一个网站是安全的</li>
<li>SSL证书是什么</li>
<li>SSL是如何工作的</li>
<li>如何给我的网站申请SSL</li>
<li>在哪里申请SSL证书</li>
<li>可以免费获取SSL证书吗</li>
<li>HTTPS和HTTP的主要区别</li>
<li>总结</li>
</ol>
<h2 id="http">什么是HTTP</h2>
<p>超文本传输协议（HTTP）是浏览器和你想要访问的网站（web服务器）之间的一种沟通方法。</p>
<p>协议允许你通过浏览器从服务器获取你想要的信息。</p>
<p>通过类比来了解HTTP和HTTPS是一个很好的办法。我们都知道浏览器和服务器是通过HTTP来进行通信的。HTTP通常是纯文本。就好比世界上大多数人都说英语，如果一个黑客知道怎么说英语，并且黑进了你的电脑，这样他就可以很轻易地获取你的密码。</p>
<p>但是在肯尼亚，我们的母语是图尔卡纳语。如果你不了解这门语言，并且在肯尼亚发现两个图尔卡纳人在对话，你就会听不懂他们在说什么。</p>
<p>这就是HTTPS的精华所在。它做了加密处理，理论上黑客不知道浏览器和服务器之间发生了什么通信。</p>
<p><img src="https://user-images.githubusercontent.com/33565767/178446926-d904cc04-57cd-4427-bdcc-e76c35f8b51b.png" alt="Client to server" title="client/browser communicating with server" width="1054" height="484" loading="lazy"></p>
<p>如果我登陆了<a href="http://www.google.com">http://www.google.com</a>，我会看到谷歌的默认页面。</p>
<p><img src="https://user-images.githubusercontent.com/33565767/178450768-e1fed4a5-993d-4d49-a47f-83cce6473085.png" alt="Googles default page" title="Google's default page" width="1366" height="727" loading="lazy"></p>
<p>客户端（大多数情况下是浏览器）发送一个信息，在计算机术语中叫做请求（request）。然后服务器应答，通常被称为响应（response）。</p>
<p>HTTP可以有效地发送HTML文档、图片和视频到web浏览器，方便用户观看。HTTP同样也使用HTML格式将数据传输到服务器。</p>
<p><img src="https://user-images.githubusercontent.com/33565767/178460366-d0568e2d-d107-4afe-a778-0ce1d224b176.png" alt="Where HTTP Protocol sits" title="HTTP Protocol is between the web browser(client) and the web server, which is in constant communication with the server side script and the database." width="880" height="586" loading="lazy"></p>
<h2 id="http">HTTP如何运作</h2>
<p>HTTP通过纯文本传输数据。举个例子，如果你在访问你的银行网页，这个网页使用的是HTTP，那么黑客就可以访问这个页面，并且读取任何你发送的信息。</p>
<p>此时HTTPS就派上用场了。许多公司都应用了HTTPS，确保用户安全地发送信息。我们会在后文章讨论。</p>
<h2 id="http">HTTP的特征</h2>
<ul>
<li>
<p>纯文本。在HTTP创建之初，开发者们只想解决一个问题：仅服务于文本文件。现在，HTTP已经被运用于文本以外更多地方。</p>
</li>
<li>
<p>七层协议。HTTP是网络通信OSI模型的第七层协议。第七层是应用层，也是OSI模型的最外层。 其他的层级包括物理层、数据链路层、网络层、传输层、会话层和表示层。想要了解更多OSI模型的信息，可以参考这篇<a href="https://chinese.freecodecamp.org/news/osi-model-networking-layers/">文章</a>，以及freeCodeCamp的YouTube频道里由Brain Ferrill讲解的网络工作的视频。视频中包含除了OSI以外更多精彩内容。<a href="https://www.youtube.com/watch?v=qiQR5rTSshw&amp;t=27s&amp;ab_channel=freeCodeCamp.org">Computer Networking Course - Network Engineering [CompTIA Network+ Exam Prep]</a></p>
</li>
<li>
<p>不安全。当你通过纯文本发送HTTP请求的时候，你同样也收到纯文本响应。也就是说任何可以访问这些请求和响应的人都可以读取这些信息。<br>
<img src="https://user-images.githubusercontent.com/33565767/179723161-3ec27c27-df79-4749-b810-974583cf1687.png" alt="Insecure connection" title="Insecure connection during a normal HTTP connection by the user" width="949" height="303" loading="lazy"></p>
</li>
<li>
<p>轻量。HTTP的优势在于轻量。因为没有像HTTPS一样，通过加密来保护数据，所以HTTP传输速度非常快。</p>
</li>
<li>
<p>HTTP通常在端口80监听。</p>
</li>
</ul>
<h2 id="">如何知道一个网站不安全</h2>
<p>当网站不安全的时候，Chrome通常会发出一个警告：<code>Your connection is not private</code>（你的连接不是私人的）。<br>
<img src="https://user-images.githubusercontent.com/33565767/182329336-d405d5b4-f5bb-45df-b936-aa1d04b9dffd.png" alt="HTTP Not secure" title="Your connection is not secure when going to a site that is not secure" width="1365" height="722" loading="lazy"></p>
<p>在Chrome的URL输入框内通常会显示红色的<code>Not Secure</code>（不安全）。<br>
<img src="https://user-images.githubusercontent.com/33565767/182329466-d2db68a8-7033-4f64-bb66-0665e8fc0c62.png" alt="Not secure URL image" title="URL of an insecure website" width="541" height="87" loading="lazy"></p>
<h2 id="http">所有的HTTP网站都不安全吗</h2>
<p>假设你正在浏览一个meme网站，一边滚动图片一边哈哈大笑。如果网站使用的是HTTP协议，这没什么大不了。</p>
<p>这时你觉得有些无聊了，打算登陆你的银行的网站，网站没有使用HTTPS协议，此时你就向黑客双手奉上了你的账户信息。</p>
<p>所以安全的底线是你浏览的信息是否无关紧要。如果不重要，HTTP是安全的，但是如果是需要保密的信息，HTTP就不够用。</p>
<h2 id="https">什么是HTTPS</h2>
<p>超文本传输安全协议，即HTTPS是浏览器和你登陆的网站（服务器）之间安全的通信。</p>
<h2 id="https">HTTPS如何运作</h2>
<p>HTTPS通过加密数据这样的安全协议来确保通信的安全。</p>
<p>对于大多数网站来说，拥有HTTPS的方式是获取一个SSL（Secure Sockets Layer安全套接层）或者TLS（Transport Layer Security传输层安全协议）证书。</p>
<p>现在，SSL已经兼容TLS，所以你没有必要获取一个TLS证书。</p>
<h2 id="https">HTTPS的特证</h2>
<ul>
<li>加密数据。通过TLS/SSL协议来加密数据。</li>
<li>是第四层（传输层）协议。</li>
<li>公钥和私钥的密钥交换发生在HTTPS中以加密和解密数据。</li>
<li>不如HTTP轻量。当HTTPS发生加密和解密的时候，就变得笨重。</li>
<li>HTTPS在端口443监听。</li>
</ul>
<h2 id="">加密的工作原理</h2>
<p><img src="https://user-images.githubusercontent.com/33565767/180215739-5e731309-eda1-4993-927c-c9daa400c3c5.png" alt="How encryption works" title="I am a dev from the client text passing through an encyption" width="977" height="280" loading="lazy"></p>
<p>假设我输入“I am a dev（我是一个开发者）。”当我点击发送的时候，这段文字会被加密，然后在服务器端被解密。</p>
<p>服务器端也是同样的道理。从服务器发送的响应，会先被加密处理然后再到客户端被解密。</p>
<h2 id="">如何知道一个网站是安全的</h2>
<p>检查一个网站是否是安全的，你通常可以查看URL信息栏是否有一把锁。如果有一把锁，则服务器和客户端之间的通信就是安全的。</p>
<p><img src="https://user-images.githubusercontent.com/33565767/178449484-738fb908-901d-4a61-9f8f-fa5a39029012.png" alt="Showing that the site is secure" title="A padlock that shows the site is secure on the URL" width="1144" height="692" loading="lazy"></p>
<p>当你点击这个锁的图标，就会看到安全连接的更多信息。</p>
<p><img src="https://user-images.githubusercontent.com/33565767/180213859-21460cfa-6a8c-484e-81e5-5dba4fc31f2a.png" alt="Shows site is secure" title="The URL section with more details of a secure site" width="1157" height="713" loading="lazy"></p>
<h2 id="ssl">SSL证书是什么</h2>
<p>SSL证书是一个小文件，告诉你的浏览器，比方说，freecodecamp.org是它所声称的网站，并且是可靠的。</p>
<p>证书的认证即是向客户（用户）确认他们所连接的服务器是管理该域（domain）的服务器。认证是为了使用户免受如域名欺骗这样的安全问题的影响。</p>
<p>证书包含一个公钥，并告诉你正在尝试连接的网站的所有者是谁。如果网站没有SSL证书，则无法使用TLS加密。</p>
<p>如果你是网站所有者，你可以创建自己的SSL证书（也称为自签名证书）。但这种方法的问题在于Chrome等浏览器不信任这些证书。它们倾向于信任由证书颁发机构颁发的证书。</p>
<h2 id="ssl">SSL是如何运作的</h2>
<p>SSL加密有两种类型，非对称和对称。SSL加密结合了这两种加密方式。下文会做详细介绍：</p>
<h3 id="">什么是非对称加密</h3>
<p>在非对称加密中，你拥有两把密钥：</p>
<ol>
<li>公钥</li>
<li>私钥</li>
</ol>
<p><img src="https://user-images.githubusercontent.com/33565767/181718454-847858dc-0df5-4bc5-bfaf-b6210c571d8f.png" alt="Asymmetric encryption" title="Asymmetric (Public key) encryption" width="1004" height="469" loading="lazy"></p>
<p>客户端/用户/浏览器在通信的时候给服务器提供公钥，然后通过公钥进行加密，服务器通过私钥进行解密。</p>
<p>私钥只能在该特定服务器上找到，其他任何人都没有。这就是为什么非对称加密更强大且更难破解，因为它有两个不同的密钥，私钥和公钥。这两个密钥协同工作以确保数据更安全。</p>
<p>这也是为什么这种加密的长度是1024/2048位。</p>
<h3 id="">什么是对称加密</h3>
<p>对称加密就简单很多。你只有一把密钥。客户端使用一个密钥进行加密，服务器使用相同的密钥解密数据。</p>
<p>对称加密更轻量。长度为128/256位。但与非对称相比，它更容易被入侵，这并不意味着它没有用。当我们使用SSL时，我们将非对称和对称结合起来，能够使通信更安全、更私密。</p>
<p><img src="https://user-images.githubusercontent.com/33565767/181720497-326e0dd9-5e0b-4bfb-b01a-2effec5ab9e0.png" alt="Symmetric encryption" title="How symmetric encryption works by using one key on the client side to encrypt and the same key on the server side to decrypt" width="1024" height="332" loading="lazy"></p>
<h3 id="">非对称 + 对称加密的工作原理</h3>
<p>非对称和对称的组合形成双层防护墙<br>
<img src="https://user-images.githubusercontent.com/33565767/182565306-224f199a-da88-4a68-be81-707636cc1069.png" alt="Asymmetric and Symmetric" title="How asymmetric and symmetric encryption work by client first sending a Hello to the server. The server then sends to the client, its public key and certificate in response. The client on step 3, sends a session key that is encrypted using the public key. On step 4, the server will decrypt the session key using the server's private key. Finally, step 5, the connection is established between the client and the server." width="945" height="563" loading="lazy"></p>
<p>在第一步中，服务器向浏览器发送非对称的公钥。如我们所知，非对成密匙包含一个公钥和一个私钥，因此浏览器收到公钥。</p>
<p>之后，浏览器生成一个会话密钥。</p>
<p>对称加密中客户端和服务器都只使用一个密钥。所以接下来，浏览器将生成一个本地会话密钥，是一个对称加密会话密钥。然后它将使用第一步中的非对称公钥对其进行加密。本地生成的会话密钥与公钥组合，发送到服务器。</p>
<p>然后，服务器将使用私钥解密它收到的加密会话密钥。在这个特定步骤中，服务器将使用非对称私钥来解密它收到的会话密钥。</p>
<p>现在，一旦解密发生，服务器和浏览器将使用会话密钥进行通信。会话密钥将仅用于这次特定会话。</p>
<p>假设你关闭了浏览器，并在第二天登录 —— 一切重新开始，会话密钥会再次被创建。</p>
<h2 id="ssl">如何给我的网站申请SSL</h2>
<p>如果你是网站所有者，你可以从证书颁发机构获取SSL证书。</p>
<p>然后在托管网站的Web服务器上安装证书。大多数情况下，托管网站的托管公司会为你处理此过程。</p>
<h2 id="ssl">在哪里申请SSL证书</h2>
<p>有些组织颁发安全证书，这些组织称为证书颁发机构。其中一些证书颁发机构包括：DigiCert、Comodo等。</p>
<p>许多开发人员从这些组织获得证书。由于这些组织办法的证书是使用最广泛，浏览器通常信任来自这些组织的证书。</p>
<h2 id="ssl">可以免费获取SSL证书吗</h2>
<p>Cloudflare免费提供SSL证书。它是最早采取这一行动的互联网安全公司之一。</p>
<p>如果你想申请一个，<a href="https://www.cloudflare.com/ssl/">可以点击这里</a>。</p>
<h2 id="https">HTTPS的用途</h2>
<p>HTTPS在安全性方面起到了很大的作用。没有它，传递敏感信息将成为一个巨大的挑战，尤其是当你的企业需要一种安全的通信方式时。</p>
<p>接受在线支付的网站（如电子商务网站）通常需要HTTPS。这是为了避免信用卡详细信息和登录信息等被盗 (引用: <a href="https://www.entrepreneur.com/article/281633">Tony Messer</a>)。</p>
<h2 id="httpshttp">HTTPS和HTTP的主要区别</h2>
<ul>
<li>HTTPS中启用了加密层，而HTTP中没有加密层。</li>
<li>数据在HTTPS中受到保护，而在HTTP中则不受保护。</li>
<li>当使用HTTPS时，网站在Google中的排名会提高，而使用HTTP时，不会获得任何排名提升。</li>
<li>使用HTTPS可以防止网络钓鱼，而使用HTTP没有保护。</li>
<li>使用HTTPS符合支付行业规定，但是HTTP不合规。</li>
<li>在最初几秒钟内加载HTTPS可能比加载HTTP慢。</li>
<li>获得SSL证书可能需要花钱，而HTTP没有认证成本。</li>
<li>在chrome上使用HTTPS网站更方便，使用HTTP网站会经常收到不安全提示。</li>
</ul>
<h2 id="">总结</h2>
<p>HTTP和HTTPS在开发者的日常生活中扮演了重要的角色，浏览器和服务器之间的通信是我们工作的动力。</p>
<p>尽可能地保护用户的数据，以防止他们的信息被盗，将获得用户的信任并提供更好的用户体验。</p>
<p>下篇文章见。</p>
<!--kg-card-end: markdown--> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 详解 HTTP、HTTPS 和 HTTP2 ]]>
                </title>
                <description>
                    <![CDATA[ 你知道 HTTP 和 HTTPS 的区别吗？如果你想了解更多的计算机网络基础知识，那么你可能会想弄清楚这些概念。 在这篇文章中，我将尽量用通俗易懂的方式来向读者讲述 HTTP 的知识。我建议大家在学习 HTTP 知识的时候，利用 Chrome 开发者工具来做实践，这可以帮助我们理解得更深刻。 此图是在网上找来的，侵删HTTP 概述 HTTP 超文本传输​​协议是位于 TCP/IP 体系结构中的应用层协议，它是万维网数据通信的基础。 当我们访问一个网站时，需要通过统一资源定位符（uniform resource locator，URL）来定位服务器并获取资源。 <协议>://<域名>:<端口>/<路径> 一个 URL 的一般形式通常如上所示（http://test.com/index.html ），现在最常用的协议就是 HTTP，HTTP 的默认端口是 80，通常可以省略。 HTTP/1.1 HTTP/1.1 是目前使用最广泛的版本，一般没有特别标明版本都是指 HTTP/1.1。 HTTP 连接建立过程 我们来看一下在浏览器输入 URL 后获取 HTML 页面的过程。   ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/http-https-and-http2/</link>
                <guid isPermaLink="false">5fb235e95f583f056509114b</guid>
                
                    <category>
                        <![CDATA[ HTTP ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTTPS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ 计算机网络 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ woai3c ]]>
                </dc:creator>
                <pubDate>Thu, 19 Aug 2021 07:20:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/04/photo-1593642533144-3d62aa4783ec-1.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>你知道 HTTP 和 HTTPS 的区别吗？如果你想了解更多的计算机网络基础知识，那么你可能会想弄清楚这些概念。</p><p>在这篇文章中，我将尽量用通俗易懂的方式来向读者讲述 HTTP 的知识。我建议大家在学习 HTTP 知识的时候，利用 Chrome 开发者工具来做实践，这可以帮助我们理解得更深刻。</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://pic2.zhimg.com/80/v2-8d547f61a175c4e6cc05ad90a7406791_720w.jpg" class="kg-image" alt="v2-8d547f61a175c4e6cc05ad90a7406791_720w" width="600" height="400" loading="lazy"><figcaption>此图是在网上找来的，侵删</figcaption></figure><h2 id="http-">HTTP 概述</h2><p>HTTP 超文本传输​​协议是位于 TCP/IP 体系结构中的应用层协议，它是万维网数据通信的基础。</p><p>当我们访问一个网站时，需要通过统一资源定位符（uniform resource locator，URL）来定位服务器并获取资源。</p><pre><code class="language-text">&lt;协议&gt;://&lt;域名&gt;:&lt;端口&gt;/&lt;路径&gt;</code></pre><p>一个 URL 的一般形式通常如上所示（<code>http://test.com/index.html</code> ），现在最常用的协议就是 HTTP，HTTP 的默认端口是 80，通常可以省略。</p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-91035fa397152281c18e1a2f9ece81f4_720w.jpg" class="kg-image" alt="v2-91035fa397152281c18e1a2f9ece81f4_720w" width="600" height="400" loading="lazy"></figure><h2 id="http-1-1">HTTP/1.1</h2><p>HTTP/1.1 是目前使用最广泛的版本，一般没有特别标明版本都是指 HTTP/1.1。</p><h3 id="http--1">HTTP 连接建立过程</h3><p>我们来看一下在浏览器输入 URL 后获取 HTML 页面的过程。</p><ol><li>先通过<a href="https://link.zhihu.com/?target=https%3A//baike.baidu.com/item/%25E5%259F%259F%25E5%2590%258D%25E7%25B3%25BB%25E7%25BB%259F%25EF%25BC%2588%25E6%259C%258D%25E5%258A%25A1%25EF%25BC%2589%25E5%258D%258F%25E8%25AE%25AE/15134609%3Ffromtitle%3Ddns%26fromid%3D427444" rel="nofollow noreferrer">域名系统（Domain Name System，DNS）</a>查询将域名转换为 IP 地址。即将 <code>test.com</code> 转换为 <code>221.239.100.30</code> 这一过程。</li><li>通过三次握手（稍后会讲）建立 TCP 连接。</li><li>发起 HTTP 请求。</li><li>目标服务器接收到 HTTP 请求并处理。</li><li>目标服务器往浏览器发回 HTTP 响应。</li><li>浏览器解析并渲染页面。</li></ol><p>下图中的 RTT 为往返时延（Round-Trip Time： 往返时延。表示从发送端发送数据开始，到发送端收到来自接收端的确认，总共经历的时延）。<br></p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-ddcb4a085bbde7f8bf80f792d4ac7e48_720w.jpg" class="kg-image" alt="v2-ddcb4a085bbde7f8bf80f792d4ac7e48_720w" width="600" height="400" loading="lazy"></figure><h3 id="http--2">HTTP 连接拆除过程</h3><p>所有 HTTP 客户端（浏览器）、服务器都可在任意时刻关闭 TCP 连接。通常会在一条报文结束时关闭连接，但出错的时候，也可能在首部行的中间或其他任意位置关闭连接。</p><h3 id="tcp-">TCP 三次握手和四次挥手</h3><p>由于 HTTP 是基于 TCP 的，所以打算在这补充一下 TCP 连接建立和拆除的过程。</p><p>首先，我们需要了解一些 TCP 报文段的字段和标志位：</p><ol><li>32 比特的序号字段和确认号字段，TCP 字节流每一个字节都按顺序编号。确认号是接收方期望从对方收到的下一字节的序号。</li><li>ACK 标志位，用于指示确认字段中的值是有效的 ACK=1 有效，ACK=0 无效。</li><li>SYN 标志位，用于连接建立，SYN 为 1 时，表明这是一个请求建立连接报文。</li><li>FIN 标志位，用于连接拆除，FIN 为 1 时，表明发送方数据已发送完毕，并要求释放连接。<br></li></ol><figure class="kg-card kg-image-card"><img src="https://pic4.zhimg.com/80/v2-578eeb6309c44c4607344fe019dff19b_720w.jpg" class="kg-image" alt="v2-578eeb6309c44c4607344fe019dff19b_720w" width="600" height="400" loading="lazy"></figure><h3 id="tcp--1">TCP 三次握手建立连接</h3><p>TCP 标准规定，ACK 报文段可以携带数据，但不携带数据就不用消耗序号。</p><ol><li>客户端发送一个不包含应用层数据的 TCP 报文段，首部的 SYN 置为 1，随机选择一个初始序号（一般为 0）放在 TCP 报文段的序号字段中。（SYN 为 1 的时候，不能携带数据，但要消耗掉一个序号）</li><li>TCP 报文段到达服务器主机后，服务器提取报文段，并为该 TCP 连接分配缓存和变量。然后向客户端发送允许连接的 ACK 报文段（不包含应用层数据）。这个报文段的首部包含 4 个信息：ACK 置 为 1，SYN 置为 1；确认号字段置为客户端的序号 + 1；随机选择自己的初始序号（一般为 0）。</li><li>收到服务器的 TCP 响应报文段后，客户端也要为该 TCP 连接分配缓存和变量，并向服务器发送一个 ACK 报文段。这个报文段将服务器端的序号 + 1 放置在确认号字段中，用来对服务器允许连接的报文段进行响应，因为连接已经建立，所以 SYN 置为 0。最后一个阶段，报文段可以携带客户到服务器的数据。并且以后的每一个报文段，SYN 都置为 0。</li></ol><p>下图是一个具体的示例：<br></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://pic2.zhimg.com/80/v2-eb4981e4f58f1822c00d7d290d14ee51_720w.jpg" class="kg-image" alt="v2-eb4981e4f58f1822c00d7d290d14ee51_720w" width="600" height="400" loading="lazy"><figcaption>此截图是我使用 Wireshark 抓包工具截取的 TCP 报文段截图</figcaption></figure><h3 id="tcp--2">TCP 四次挥手拆除连接</h3><p>FIN 报文段即使不携带数据，也要消耗序号。</p><ol><li>客户端发送一个 FIN 置为 1 的报文段。</li><li>服务器回送一个确认报文段。</li><li>服务器发送 FIN 置为 1 的报文段。</li><li>客户端回送一个确认报文段。</li></ol><h3 id="tcp--3">TCP 为什么是四次挥手，而不是三次？</h3><ol><li>当 A 给 B 发送 FIN 报文时，代表 A 不再发送报文，但仍可以接收报文。</li><li>B 可能还有数据需要发送，因此先发送 ACK 报文，告知 A “我知道你想断开连接的请求了”。这样 A 便不会因为没有收到应答而继续发送断开连接的请求（即 FIN 报文）。</li><li>B 在处理完数据后，就向 A 发送一个 FIN 报文，然后进入 LAST_ACK 阶段（超时等待）。</li><li>A 向 B 发送 ACK 报文，双方都断开连接。</li></ol><p>参考资料：</p><ul><li><a href="https://www.zhihu.com/question/63264012">知乎网友-魔方的回答</a></li></ul><h3 id="http--3">HTTP 报文格式</h3><p>HTTP 报文由请求行、首部、实体主体组成，它们之间由 CRLF（回车换行符） 分隔开。</p><p><strong>注意：实体包括首部(也称为实体首部)和实体主体，sp 即是空格 space</strong>。<br></p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-392bc8d0de5ac6d44dd520ca4e42afc8_720w.jpg" class="kg-image" alt="v2-392bc8d0de5ac6d44dd520ca4e42afc8_720w" width="600" height="400" loading="lazy"></figure><p><br>请求行和首部是由 ASCII 文本组成的，实体主体是可选的，可以为空也可以是任意二进制数据。</p><p>请求报文和响应报文的格式基本相同。</p><p><strong>请求报文格式</strong>：</p><pre><code class="language-text">&lt;method&gt; &lt;request-URL&gt; &lt;version&gt;
&lt;headers&gt;
&lt;entity-body&gt;</code></pre><p><strong>响应报文格式</strong>：</p><pre><code class="language-text">&lt;version&gt; &lt;status&gt; &lt;reason-phrase&gt;
&lt;headers&gt;
&lt;entity-body&gt;</code></pre><p><strong>一个请求或响应报文由以下字段组成</strong>：</p><ol><li>请求方法，客户端希望服务器对资源执行的动作。</li><li>请求 URL，命名了所请求的资源。</li><li>协议版本，报文所使用的 HTTP 版本。</li><li>状态码，这三位数字描述了请求过程中所发生的情况。</li><li>原因短语，数字状态码的可读版本（例如上面的响应示例跟在 200 后面的 OK，一般按规范写最好）。</li><li>首部，可以有零或多个首部。</li><li>实体的主体部分，可以为空也可以包含任意二进制数据。</li></ol><p><strong>一个 HTTP 请求示例</strong>：</p><pre><code class="language-text">GET /2.app.js HTTP/1.1
Host: 118.190.217.8:3389
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36
Accept: */*
Referer: http://118.190.217.8:3389/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9</code></pre><p><strong>一个 HTTP 响应示例</strong>：</p><pre><code class="language-text">HTTP/1.1 200 OK
X-Powered-By: Express
Accept-Ranges: bytes
Cache-Control: public, max-age=0
Last-Modified: Sat, 07 Mar 2020 03:52:30 GMT
ETag: W/"253e-170b31f7de7"
Content-Type: application/javascript; charset=UTF-8
Vary: Accept-Encoding
Content-Encoding: gzip
Date: Fri, 15 May 2020 05:38:05 GMT
Connection: keep-alive
Transfer-Encoding: chunked</code></pre><h3 id="-">方法</h3><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-1eff029d1e35612fb85ad1d6765d50c4_720w.jpg" class="kg-image" alt="v2-1eff029d1e35612fb85ad1d6765d50c4_720w" width="600" height="400" loading="lazy"></figure><h3 id="get-head">GET 和 HEAD</h3><p>其中 GET 和 HEAD 被称为安全方法，因为它们是幂等的（如果一个请求不管执行多少次，其结果都是一样的，这个请求就是<strong>幂等的</strong>），类似于 POST 就不是幂等的。</p><p>HEAD 方法和 GET 方法很类似，但服务器在响应中只返回首部。这就允许客户端在未获取实际资源的情况下，对资源的首部进行检查。使用 HEAD，可以：</p><ol><li>在不获取资源的情况下了解资源的情况。</li><li>通过查看响应状态码，看看某个对象是否存在。</li><li>通过查看首部，了解测试资源是否被修改了。</li></ol><p>服务器开发者必须确保返回的首部与 GET 请求所返回的首部完全相同。遵循 HTTP/1.1 规范，就必须实现 HEAD 方法。</p><h3 id="put">PUT</h3><p>与 GET 方法从服务器读取文档相反，PUT 方法会向服务器写入文档。PUT 方法的语义就是让服务器用请求的主体部分来创建一个由所请求的 URL 命名的新文档。 如果那个文档已存在，就覆盖它。</p><h3 id="post">POST</h3><p>POST 方法通常用来向服务器发送表单数据。</p><h3 id="trace">TRACE</h3><p>客户端发起一个请求时，这个请求可能要穿过路由器、防火墙、代理、网关等。每个中间节点都可能会修改原始的 HTTP 请求，TRACE 方法允许客户端在最终发起请求时，看看它变成了什么样子。</p><p>TRACE 请求会在目的服务器端发起一个“环回”诊断。行程最后一站的服务器会弹回一条 TRACE 响应，并在响应主体中携带它收到的原始请求报文。 这样客户端就可以查看在所有中间 HTTP 应用程序组成的请求/响应链上，原始报文是否被毁坏或修改过。<br></p><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-f66c499fa15d2ae881c5aec8d3ee70be_720w.jpg" class="kg-image" alt="v2-f66c499fa15d2ae881c5aec8d3ee70be_720w" width="600" height="400" loading="lazy"></figure><p>TRACE 方法主要用于诊断，用于验证请求是否如愿穿过了请求/响应链。它也是一种工具，用来查看代理和其他应用程序对用户请求所产生的效果。 TRACE 请求中不能带有实体的主体部分。TRACE 响应的实体主体部分包含了响应服务器收到的请求的精确副本。</p><h3 id="options">OPTIONS</h3><p>OPTIONS 方法请求 Web 服务器告知其支持的各种功能。</p><h3 id="delete">DELETE</h3><p>DELETE 方法就是让服务器删除请求 URL 所指定的资源。</p><h3 id="--1">状态码</h3><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-aff02263117f428811e86b71ad01ec7a_720w.jpg" class="kg-image" alt="v2-aff02263117f428811e86b71ad01ec7a_720w" width="600" height="400" loading="lazy"></figure><h3 id="300-399-">300~399 重定向状态码</h3><p>重定向状态码要么告诉客户端使用替代位置来访问他们感兴趣的资源，要么提供一个替代的响应而不是资源的内容。 如果资源已被移动，可以发送一个重定向状态码和一个可选的 Location 首部来告知客户端资源已被移走，以及现在在哪里可以找到它。这样，浏览器可以在不打扰使用者的情况下，透明地转入新的位置。</p><h3 id="400-499-">400~499 客户端错误状态码</h3><p>有时客户端会发送一些服务器无法处理的东西，例如格式错误的请求报文、一个不存在的 URL。</p><h3 id="500-599-">500~599 服务器错误状态码</h3><p>有时客户端发送了一条有效请求，服务器自身却出错了。</p><h3 id="--2">首部</h3><p>首部和方法共同配合工作，决定了客户端和服务器能做什么事情。</p><p><strong>首部分类</strong>：</p><ol><li>通用首部，可以出现在请求或响应报文中。</li><li>请求首部，提供更多有关请求的信息。</li><li>响应首部，提供更多有关响应的信息。</li><li>实体首部，描述主体的长度和内容，或者资源自身。</li><li>扩展首部，规范中没有定义的新首部。</li></ol><h3 id="--3">通用首部</h3><p>有些首部提供了与报文相关的最基本信息，它们被称为通用首部。以下是一些常见的通用首部：<br></p><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-2f7b70e0538ccfed82cb4bea696b5f79_720w.jpg" class="kg-image" alt="v2-2f7b70e0538ccfed82cb4bea696b5f79_720w" width="600" height="400" loading="lazy"></figure><h3 id="--4"><br>请求首部</h3><p>请求首部是只在请求报文中有意义的首部，用于说明请求的详情。以下是一些常见的请求首部：</p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-bd43f3dbc08e9df61b77041526831854_720w.jpg" class="kg-image" alt="v2-bd43f3dbc08e9df61b77041526831854_720w" width="600" height="400" loading="lazy"></figure><h3 id="--5">响应首部</h3><p>响应首部让服务器为客户端提供了一些额外的信息。</p><h3 id="--6">实体首部</h3><p>实体首部提供了有关实体及其内容的大量信息，从有关对象类型的信息，到能够对资源使用的各种有效的请求方法。</p><p>例如<strong>内容首部</strong>，提供了与实体内容有关的特定信息，说明了其类型、尺寸以及处理它所需的其他有用信息。 另外，通用的缓存首部说明了如何或什么时候进行缓存。<strong>实体的缓存首部</strong>提供了与被缓存实体有关的信息。</p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-97b2ecf5532a21f520742cc0edb2f634_720w.jpg" class="kg-image" alt="v2-97b2ecf5532a21f520742cc0edb2f634_720w" width="600" height="400" loading="lazy"></figure><h3 id="--7">性能优化</h3><h3 id="1-http-">1. 减少 HTTP 请求</h3><p>每发起一个 HTTP 请求，都得经历三次握手建立 TCP 连接，如果连接只用来交换少量数据，这个过程就会严重降低 HTTP 性能。所以我们可以将多个小文件合成一个大文件，从而减少 HTTP 请求次数。</p><p>其实由于持久连接（重用 TCP 连接，以消除连接及关闭时延；HTTP/1.1 默认开启持久连接）的存在，每个新请求不一定都需要建立一个新的 TCP 连接。但是，浏览器处理完一个 HTTP 请求才能发起下一个，所以在 TCP 连接数没达到浏览器规定的上限时，还是会建立新的 TCP 连接。从这点来看，减少 HTTP 请求仍然是有必要的。</p><h3 id="2-cdn">2. 静态资源使用 CDN</h3><p>内容分发网络（CDN）是一组分布在多个不同地理位置的 Web 服务器。我们都知道，当服务器离用户越远时，延迟越高。CDN 就是为了解决这一问题，在多个位置部署服务器，让用户离服务器更近，从而缩短请求时间。</p><h3 id="3-">3. 善用缓存</h3><p>为了避免用户每次访问网站都得请求文件，我们可以通过添加 Expires 头来控制这一行为。Expires 设置了一个时间，只要在这个时间之前，浏览器都不会请求文件，而是直接使用缓存。</p><p>不过这样会产生一个问题，当文件更新了怎么办？怎么通知浏览器重新请求文件？</p><p>可以通过更新页面中引用的资源链接地址，让浏览器主动放弃缓存，加载新资源。</p><p>具体做法是把资源地址 URL 的修改与文件内容关联起来，也就是说，只有文件内容变化，才会导致相应 URL 的变更，从而实现文件级别的精确缓存控制。什么东西与文件内容相关呢？我们会很自然的联想到利用<a href="https://link.zhihu.com/?target=https%3A//baike.baidu.com/item/%25E6%25B6%2588%25E6%2581%25AF%25E6%2591%2598%25E8%25A6%2581%25E7%25AE%2597%25E6%25B3%2595/3286770%3Ffromtitle%3D%25E6%2591%2598%25E8%25A6%2581%25E7%25AE%2597%25E6%25B3%2595%26fromid%3D12011257" rel="nofollow noreferrer">数据摘要要算法</a>对文件求摘要信息，摘要信息与文件内容一一对应，就有了一种可以精确到单个文件粒度的缓存控制依据了。</p><p>参考资料：</p><ul><li><a href="https://www.zhihu.com/question/20790576/answer/32602154">张云龙--大公司里怎样开发和部署前端代码？</a></li></ul><h3 id="4-">4. 压缩文件</h3><p>压缩文件可以减少文件下载时间，让用户体验性更好。</p><p>gzip 是目前最流行和最有效的压缩方法。可以通过向 HTTP 请求头中的 Accept-Encoding 头添加 gzip 标识来开启这一功能。当然，服务器也得支持这一功能。</p><p>举个例子，我用 Vue 开发的项目构建后生成的 app.js 文件大小为 1.4MB，使用 gzip 压缩后只有 573KB，体积减少了将近 60%。</p><h3 id="5-max-age-no-cache-">5. 通过 max-age 和 no-cache 实现文件精确缓存</h3><p>通用消息头部 <code>Cache-Control</code> 其中有两个选项：</p><ol><li><code>max-age</code>: 设置缓存存储的最大周期，超过这个时间缓存被认为过期(单位秒)。在这个时间前，浏览器读取文件不会发出新请求，而是直接使用缓存。</li><li><code>no-cache</code>: 指定 no-cache 表示客户端可以缓存资源，每次使用缓存资源前都必须重新验证其有效性。</li></ol><p>我们可以将那些长期不变的静态资源设置一个非常长的缓存时间，例如设置成缓存一年。</p><p>然后将 <code>index.html</code> 文件设置成 <code>no-cache</code>。这样每次访问网站时，浏览器都会询问 <code>index.html</code> 是否有更新，如果没有，就使用旧的 <code>index.html</code> 文件。如果有更新，就读取新的 <code>index.html</code> 文件。当加载新的 <code>index.html</code> 时，也会去加载里面新的 URL 资源。</p><p>例如 <code>index.html</code> 原来引用了 <code>a.js</code> 和 <code>b.js</code>，现在更新了变成 <code>a.js</code> 和 <code>c.js</code>。那就只会加载 <code>c.js</code> 文件。</p><p>具体请看 <a href="https://link.zhihu.com/?target=https%3A//github.com/woai3c/node-blog/blob/master/doc/node-blog7.md" rel="nofollow noreferrer">webpack + express 实现文件精确缓存</a>。</p><h2 id="https">HTTPS</h2><p>HTTPS 是最流行的 HTTP 安全形式，由网景公司首创，所有主要的浏览器和服务器都支持此协议。 使用 HTTPS 时，所有的 HTTP 请求和响应数据在发送之前，都要进行加密。加密可以使用 SSL 或 TLS。</p><figure class="kg-card kg-image-card"><img src="https://pic4.zhimg.com/80/v2-bb65d4c1c08bffc3a1e10968e18911f7_720w.jpg" class="kg-image" alt="v2-bb65d4c1c08bffc3a1e10968e18911f7_720w" width="600" height="400" loading="lazy"></figure><p>SSL/TLS 协议作用在 HTTP 协议之下，对于上层应用来说，原来的发送/接收数据流程不变，这就很好地兼容了老的 HTTP 协议。由于 SSL/TLS 差别不大，下面统一使用 SSL。</p><p>要想了解 HTTPS 为何安全，还得继续了解一下这些概念：<strong>加密算法</strong>、<strong>摘要算法</strong>、<strong>数字签名</strong>和<strong>数字证书</strong>。</p><h3 id="--8">加密算法</h3><h3 id="--9">对称密钥密码体制</h3><p>对称密钥密码体制，即加密密钥和解密密钥是使用相同的密码体制。对称密钥加密技术的缺点之一就是发送者和接收者在对话之前，一定要有一个共享的密钥，所以不太安全。</p><h3 id="--10">公钥密码体制</h3><p>公钥密码体制使用不同的加密密钥与解密密钥。公钥密码体制产生的主要原因有两个：一是对称密钥密码体制的密钥分配问题，二是对数字签名的需求。</p><p>在公钥密码体制中，加密密钥是公开的，解密密钥是需要保密的，加密算法和解密算法也是公开的。</p><p>公钥密码体制的加密和解密有如下特点：</p><ol><li><strong>密钥对产生器</strong>产生出接收者 B 的一对密钥，即加密密钥 PK 和解密密钥 SK。</li><li>发送者 A 用 B 的公钥 PK 作为加密密钥来加密信息，B 接收后用解密密钥 SK 解密。</li></ol><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-5ad7018640fb80e50e92d20484e81f86_720w.jpg" class="kg-image" alt="v2-5ad7018640fb80e50e92d20484e81f86_720w" width="600" height="400" loading="lazy"></figure><p>使用对称密钥时，由于双方使用同样的密钥，因此在通信信道上可以进行一对一的双向保密通信，双方都可以用同一个密钥加密解密。</p><p>使用公开密钥时，在通信信道上可以是多对一的单向保密信道。即可以有多人持有 B 的公钥，但只有 B 才能解密。</p><h3 id="--11">摘要算法</h3><p>摘要算法的主要特征是加密过程不需要密钥，并且经过加密的数据无法被解密，目前可以被解密逆向的只有CRC32算法，只有输入相同的明文数据经过相同的消息摘要算法才能得到相同的密文。</p><h3 id="--12">数字签名</h3><p>用加密系统对报文进行签名，以说明是谁编写的报文，同时证明报文未被篡改过，这种技术称为<strong>数字签名</strong>。</p><p>数字签名是附加在报文上的特殊加密校验码。使用数字签名的好处有：</p><ol><li>签名可以证明是作者编写了这条报文。只有作者才会有最机密的私有密钥，因此，只有作者才能计算出这些校验和。</li><li>签名可以防止报文被篡改，如果有人在报文传输过程中对其进行了修改，校验和就不再匹配了。</li></ol><p>数字签名通常是用非对称公开密钥技术产生的。</p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-dbe067a589d86e584a226ddd31c49f80_720w.jpg" class="kg-image" alt="v2-dbe067a589d86e584a226ddd31c49f80_720w" width="600" height="400" loading="lazy"></figure><p>看上图，任何人都能用 A 的公钥 PK 对密文进行 E 运算后得到 A 发送的明文。可见这种通信并非为了保密，而是为了进行签名和核实签名，即确认此信息是 A 发送的（使用 A 的密钥进行加密的报文，只有使用 A 的公钥才能正确解密）。 但上述过程仅对报文进行了签名，对报文 X 本身却未保密，所以要采用下图的方法，同时实现秘密通信和数字签名。</p><figure class="kg-card kg-image-card"><img src="https://pic4.zhimg.com/80/v2-113d720a3ca11d8d18ead0a54ac00e43_720w.jpg" class="kg-image" alt="v2-113d720a3ca11d8d18ead0a54ac00e43_720w" width="600" height="400" loading="lazy"></figure><h3 id="--13">数字证书</h3><p>假如你想访问一个网站，怎么确保对方给你的公钥是你想访问的网站的公钥，而不是被中间人篡改过的？</p><p>数字证书的出现就是为了解决这个问题，它是由数字证书认证机构颁发的，用来证明公钥拥有者的身份。换句话说，数字证书的作用就相当于人的身份证，身份证证明了张三就是张三，而不是别人。</p><p><strong>数字证书一般包含以下内容</strong>：</p><ol><li>对象的名称（人、服务器、组织等）；</li><li>过期时间；</li><li>证书发布者（由谁为证书担保）；</li><li>来自证书发布者的数字签名；</li><li>对象的公钥；</li><li>对象和所用签名算法的描述性信息。</li></ol><p>任何人都可以创建一个数字证书，但由谁来担保才是重点。</p><p><strong>数字证书的数字签名计算过程</strong>：</p><ol><li>用摘要算法对数字证书的内容计算出摘要；</li><li>用数字证书的私钥对摘要进行加密得到数字签名。</li></ol><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-17ec75ef0f9ff1892eb6aada2c3d44e9_720w.jpg" class="kg-image" alt="v2-17ec75ef0f9ff1892eb6aada2c3d44e9_720w" width="600" height="400" loading="lazy"></figure><p>当浏览器收到证书时，会对签名颁发机构进行验证，如果颁发机构是个很有权威的公共签名机构，浏览器可能就知道其公开密钥了（浏览器会预装很多签名颁发机构的证书）。如果对签名颁发机构一无所知，浏览器通常会向用户显示一个对话框，看看他是否相信这个签名发布者。</p><p>因为数字证书的公钥是公开的，任何人都可以用公钥解密出数字证书的数字签名的摘要，然后再用同样的摘要算法对证书内容进行摘要计算，将得出的摘要和解密后的摘要作对比，如果内容一致则说明这个证书没有被篡改过，可以信任。</p><p>这个过程是建立在被大家所认可的证书机构之上得到的公钥，所以这是一种安全的方式。</p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-be99bd75b57e167a6dd28534c6070574_720w.jpg" class="kg-image" alt="v2-be99bd75b57e167a6dd28534c6070574_720w" width="600" height="400" loading="lazy"></figure><h3 id="https-">HTTPS 连接建立过程</h3><p>HTTPS 连接建立过程和 HTTP 差不多，区别在于 HTTP（默认端口 80） 请求只要在 TCP 连接建立后就可以发起，而 HTTPS（默认端口 443） 在 TCP 连接建立后，还需要经历 SSL 协议握手，成功后才能发起请求。</p><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-ee3edd71c7aa0e6434f271aa71852335_720w.jpg" class="kg-image" alt="v2-ee3edd71c7aa0e6434f271aa71852335_720w" width="600" height="400" loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-0adc50b67e0be922b2a9d6de861f1c95_720w.jpg" class="kg-image" alt="v2-0adc50b67e0be922b2a9d6de861f1c95_720w" width="600" height="400" loading="lazy"></figure><p>我知道肯定会有人不满足于简化版的 SSL 握手过程，所以我找了一篇文章<a href="https://link.zhihu.com/?target=https%3A//www.jianshu.com/p/7158568e4867" rel="nofollow noreferrer">SSL/TLS 握手过程详解</a>，这篇文章非常详细的讲解了 SSL 握手的每一步骤。建议有兴趣的同学看一看。</p><h2 id="http-2">HTTP/2</h2><p>HTTP/2 是 HTTP/1.x 的扩展，而非替代。所以 HTTP 的语义不变，提供的功能不变，HTTP 方法、状态码、URL 和首部字段等这些核心概念也不变。</p><p>之所以要递增一个大版本到 2.0，主要是因为它改变了客户端与服务器之间交换数据的方式。HTTP 2.0 增加了新的二进制分帧数据层，而这一层并不兼容之前的 HTTP 1.x 服务器及客户端——是谓 2.0。</p><h3 id="http-2-">HTTP/2 连接建立过程</h3><p>现在的主流浏览器 HTTP/2 的实现都是基于 SSL/TLS 的，也就是说使用 HTTP/2 的网站都是 HTTPS 协议的，所以本文只讨论基于 SSL/TLS 的 HTTP/2 连接建立过程。</p><p>基于 SSL/TLS 的 HTTP/2 连接建立过程和 HTTPS 差不多。在 SSL/TLS 握手协商过程中，客户端在 ClientHello 消息中设置 ALPN（应用层协议协商）扩展来表明期望使用 HTTP/2 协议，服务器用同样的方式回复。通过这种方式，HTTP/2 在 SSL/TLS 握手协商过程中就建立起来了。</p><h3 id="http-1-1-">HTTP/1.1 的问题</h3><h3 id="1-">1. 队头阻塞</h3><p>在 HTTP 请求应答过程中，如果出现了某种情况，导致响应一直未能完成，那后面所有的请求就会一直阻塞着，这种情况叫队头阻塞。</p><h3 id="2-tcp-">2. 低效的 TCP 利用</h3><p>由于 <a href="https://link.zhihu.com/?target=https%3A//baike.baidu.com/item/%25E6%2585%25A2%25E5%2590%25AF%25E5%258A%25A8/8242395" rel="nofollow noreferrer">TCP 慢启动机制</a>，导致每个 TCP 连接在一开始的时候传输速率都不高，在处理多个请求后，才会慢慢达到“合适”的速率。对于请求数据量很小的 HTTP 请求来说，这种情况就是种灾难。</p><h3 id="3--1">3. 臃肿的消息首部</h3><p>HTTP/1.1 的首部无法压缩，再加上 cookie 的存在，经常会出现首部大小比请求数据大小还大的情况。</p><h3 id="4--1">4. 受限的优先级设置</h3><p>HTTP/1.1 无法为重要的资源指定优先级，每个 HTTP 请求都是一视同仁。</p><p>在继续讨论 HTTP/2 的新功能之前，先把 HTTP/1.1 的问题列出来是有意义的。因为 HTTP/2 的某些新功能就是为了解决上述某些问题而产生的。</p><h3 id="--14">二进制分帧层</h3><p>HTTP/2 是基于帧的协议。采用分帧是为了将重要信息封装起来，让协议的解析方可以轻松阅读、解析并还原信息。</p><p>而 HTTP/1.1 是以文本分隔的。解析 HTTP/1.1 不需要什么高科技，但往往速度慢且容易出错。你需要不断地读入字节，直到遇到分隔符 CRLF 为止，同时还要考虑不守规矩的客户端，它只会发送 LF。</p><p>解析 HTTP/1.1 的请求或响应还会遇到以下问题：</p><ol><li>一次只能处理一个请求或响应，完成之前不能停止解析。</li><li>无法预判解析需要多少内存。</li></ol><p>HTTP/2 有了帧，处理协议的程序就能预先知道会收到什么，并且 HTTP/2 有表示帧长度的字段。</p><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-b5e21a1d51a86e69835cf4fc2b0ead6d_720w.jpg" class="kg-image" alt="v2-b5e21a1d51a86e69835cf4fc2b0ead6d_720w" width="600" height="400" loading="lazy"></figure><h3 id="--15">帧结构</h3><pre><code class="language-text">+-----------------------------------------------+
 |                 Length (24)                   |
 +---------------+---------------+---------------+
 |   Type (8)    |   Flags (8)   |
 +-+-------------+---------------+-------------------------------+
 |R|                 Stream Identifier (31)                      |
 +=+=============================================================+
 |                   Frame Payload (0...)                      ...
 +---------------------------------------------------------------+</code></pre><figure class="kg-card kg-image-card"><img src="https://pic4.zhimg.com/80/v2-7f7d60db1b3a2d3ff25b613a4cbeaa97_720w.jpg" class="kg-image" alt="v2-7f7d60db1b3a2d3ff25b613a4cbeaa97_720w" width="600" height="400" loading="lazy"></figure><p>由于 HTTP/2 是分帧的，请求和响应都可以多路复用，有助于解决类似类似队头阻塞的问题。</p><h3 id="--16">帧类型</h3><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-de35fa232ac8c4b181ede6f7af13925d_720w.jpg" class="kg-image" alt="v2-de35fa232ac8c4b181ede6f7af13925d_720w" width="600" height="400" loading="lazy"></figure><h3 id="--17">多路复用</h3><p>在 HTTP/1.1 中，如果客户端想发送多个并行的请求，那么必须使用多个 TCP 连接。</p><p>而 HTTP/2 的二进制分帧层突破了这一限制，所有的请求和响应都在同一个 TCP 连接上发送：客户端和服务器把 HTTP 消息分解成多个帧，然后乱序发送，最后在另一端再根据流 ID 重新组合起来。</p><p>这个机制为 HTTP 带来了巨大的性能提升，因为：</p><ul><li>可以并行交错地发送请求，请求之间互不影响；</li><li>可以并行交错地发送响应，响应之间互不干扰；</li><li>只使用一个连接即可并行发送多个请求和响应；</li><li>消除不必要的延迟，从而减少页面加载的时间；</li><li>不必再为绕过 HTTP 1.x 限制而多做很多工作；</li></ul><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-369330c2d4712cb12cdb7124ec691931_720w.jpg" class="kg-image" alt="v2-369330c2d4712cb12cdb7124ec691931_720w" width="600" height="400" loading="lazy"></figure><h3 id="--18">流</h3><p>HTTP/2 规范对流的定义是：HTTP/2 连接上独立的、双向的帧序列交换。如果客户端想要发出请求，它会开启一个新流，然后服务器在这个流上回复。 由于有分帧，所以多个请求和响应可以交错，而不会互相阻塞。流 ID 用来标识帧所属的流。</p><p>客户端到服务器的 HTTP/2 连接建立后，通过发送 HEADERS 帧来启动新的流。如果首部需要跨多个帧，可能还会发送 CONTINUATION 帧。该 HEADERS 帧可能来自请求或响应。 后续流启动的时候，会发送一个带有递增流 ID 的新 HEADERS 帧。</p><h3 id="--19">消息</h3><p>HTTP 消息泛指 HTTP 请求或响应，消息由一或多个帧组成，这些帧可以乱序发送，然后再根据每个帧首部的流 ID 重新组装。</p><p>一个消息至少由 HEADERS 帧（它初始化流）组成，并且可以另外包含 CONTINUATION 和 DATA 帧，以及其他的 HEADERS 帧。</p><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-b42c13b2eb2f9e68fa6c525b0c2ec1ba_720w.jpg" class="kg-image" alt="v2-b42c13b2eb2f9e68fa6c525b0c2ec1ba_720w" width="600" height="400" loading="lazy"></figure><p>HTTP/1.1 的请求和响应部分都分成消息首部和消息体两部分；HTTP/2 的请求和响应分成 HEADERS 帧和 DATA 帧。</p><h3 id="--20">优先级</h3><p>把 HTTP 消息分解为很多独立的帧之后，就可以通过优化这些帧的交错和传输顺序，进一步提升性能。</p><p>通过 HEADERS 帧和 PRIORITY 帧，客户端可以明确地和服务器沟通它需要什么，以及它需要这些资源的顺序。具体来讲，服务器可以根据流的优先级，控制资源分配（CPU、内存、带宽），而在响应数据准备好之后，优先将最高优先级的帧发送给客户端。</p><h3 id="--21">流量控制</h3><p>在同一个 TCP 连接上传输多个数据流，就意味着要共享带宽。标定数据流的优先级有助于按序交付，但只有优先级还不足以确定多个数据流或多个连接间的资源分配。</p><p>为解决这个问题，HTTP/2 为数据流和连接的流量控制提供了一个简单的机制：</p><ul><li>流量控制基于每一跳进行，而非端到端的控制；</li><li>流量控制基于 WINDOW_UPDATE 帧进行，即接收方广播自己准备接收某个数据流的多少字节，以及对整个连接要接收多少字节；</li><li>流量控制窗口大小通过 WINDOW_UPDATE 帧更新，这个字段指定了流 ID 和窗口大小递增值；</li><li>流量控制有方向性，即接收方可能根据自己的情况为每个流乃至整个连接设置任意窗口大小；</li><li>流量控制可以由接收方禁用，包括针对个别的流和针对整个连接。</li></ul><p>HTTP/2 连接建立之后，客户端与服务器交换 SETTINGS 帧，目的是设置双向的流量控制窗口大小。除此之外，任何一端都可以选择禁用个别流或整个连接的流量控制。</p><h3 id="--22">服务器推送</h3><p>HTTP/2 新增的一个强大的新功能，就是服务器可以对一个客户端请求发送多个响应。换句话说，除了对最初请求的响应外，服务器还可以额外向客户端推送资源，而无需客户端明确地请求。</p><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-d4e4f7bbaa1d8d2707951dfa993291e2_720w.jpg" class="kg-image" alt="v2-d4e4f7bbaa1d8d2707951dfa993291e2_720w" width="600" height="400" loading="lazy"></figure><p>为什么需要这样一个机制呢？通常的 Web 应用都由几十个资源组成，客户端需要分析服务器提供的文档才能逐个找到它们。那为什么不让服务器提前就把这些资源推送给客户端，从而减少额外的时间延迟呢？服务器已经知道客户端下一步要请求什么资源了，这时候服务器推送即可派上用场。</p><p>另外，客户端也可以拒绝服务器的推送。</p><h3 id="--23">首部压缩</h3><p>HTTP/1.1 存在的一个问题就是臃肿的首部，HTTP/2 对这一问题进行了改进，可以对首部进行压缩。 在一个 Web 页面中，一般都会包含大量的请求，而其中有很多请求的首部往往有很多重复的部分。</p><p>例如有如下两个请求：</p><pre><code class="language-text">:authority: unpkg.zhimg.com
:method: GET
:path: /za-js-sdk@2.16.0/dist/zap.js
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: zh-CN,zh;q=0.9
cache-control: no-cache
pragma: no-cache
referer: https://www.zhihu.com/
sec-fetch-dest: script
sec-fetch-mode: no-cors
sec-fetch-site: cross-site
user-agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36</code></pre><pre><code class="language-http">:authority: zz.bdstatic.com
:method: GET
:path: /linksubmit/push.js
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: zh-CN,zh;q=0.9
cache-control: no-cache
pragma: no-cache
referer: https://www.zhihu.com/
sec-fetch-dest: script
sec-fetch-mode: no-cors
sec-fetch-site: cross-site
user-agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36</code></pre><p>从上面两个请求可以看出来，有很多数据都是重复的。如果可以把相同的首部存储起来，仅发送它们之间不同的部分，就可以节省不少的流量，加快请求的时间。</p><p>HTTP/2 在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键－值对，对于相同的数据，不再通过每次请求和响应发送。</p><p>下面再来看一个简化的例子，假设客户端按顺序发送如下请求首部：</p><pre><code class="language-text">Header1:foo
Header2:bar
Header3:bat</code></pre><p>当客户端发送请求时，它会根据首部值创建一张表：</p><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-50b11e7a83b07c281fcfb483c576f542_720w.jpg" class="kg-image" alt="v2-50b11e7a83b07c281fcfb483c576f542_720w" width="600" height="400" loading="lazy"></figure><p>如果服务器收到了请求，它会照样创建一张表。 当客户端发送下一个请求的时候，如果首部相同，它可以直接发送这样的首部块：</p><pre><code class="language-text">62 63 64</code></pre><p>服务器会查找先前建立的表格，并把这些数字还原成索引对应的完整首部。</p><h3 id="--24">性能优化</h3><p>使用 HTTP/2 代替 HTTP/1.1，本身就是一种巨大的性能提升。 这小节要聊的是在 HTTP/1.1 中的某些优化手段，在 HTTP/2 中是不必要的，可以取消的。</p><h3 id="--25">取消合并资源</h3><p>在 HTTP/1.1 中要把多个小资源合并成一个大资源，从而减少请求。而在 HTTP/2 就不需要了，因为 HTTP/2 所有的请求都可以在一个 TCP 连接发送。</p><h3 id="--26">取消域名拆分</h3><p>取消域名拆分的理由同上，再多的 HTTP 请求都可以在一个 TCP 连接上发送，所以不需要采取多个域名来突破浏览器 TCP 连接数限制这一规则了。</p><h2 id="--27">参考资料</h2><ul><li><a href="https://link.zhihu.com/?target=https%3A//book.douban.com/subject/10746113/" rel="nofollow noreferrer">HTTP权威指南</a></li><li><a href="https://link.zhihu.com/?target=https%3A//book.douban.com/subject/27665112/" rel="nofollow noreferrer">HTTP/2基础教程</a></li><li><a href="https://link.zhihu.com/?target=https%3A//www.jianshu.com/p/7158568e4867" rel="nofollow noreferrer">SSL/TLS 握手过程详解</a></li><li><a href="https://link.zhihu.com/?target=https%3A//www.jianshu.com/p/ffe8c203a471" rel="nofollow noreferrer">互联网安全之数字签名、数字证书与PKI系统</a></li><li><a href="https://link.zhihu.com/?target=https%3A//book.douban.com/subject/26960678/" rel="nofollow noreferrer">计算机网络（第7版）</a></li><li><a href="https://link.zhihu.com/?target=https%3A//book.douban.com/subject/25856314/" rel="nofollow noreferrer">Web性能权威指南</a></li></ul><h3 id="--28"><a href="https://www.zhihu.com/people/tan-guang-zhi-19/posts">更多文章，敬请关注</a></h3> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 如何快速在本地开发环境启动 HTTPS ]]>
                </title>
                <description>
                    <![CDATA[ 如今我们访问的所有网站几乎都受 HTTPS 保护。如果你的网站还没有，那你应该考虑这么做了 [https://developers.google.com/web/fundamentals/security/encrypt-in-transit/why-https] 。使用 HTTPS 保护服务器安全还意味着你无法从不受 HTTPS 保护的服务器向该服务器发送请求。这给使用本地开发环境的开发人员带来了问题，因为这些本地开发环境都是在 http://localhost 下运行的。 我在一家创业公司里，我们决定使用 HTTPS 保护我们的 AWS Elastic Load Balancer 端点，以增强安全性。我遇到了一个问题：本地开发环境对服务器的请求被拒绝。 在谷歌进行快速搜索之后，我发现了几篇类似的文章（1 [https://devcenter.heroku.com/articles/ssl-certificate-self]，2 [https://www.kevinleary.net/self-signed-trusted-certificates-node-js-express ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/how-to-get-https-working-on-your-local-development-environment-in-5-minutes/</link>
                <guid isPermaLink="false">5fffb5675f61e30501b5bc38</guid>
                
                    <category>
                        <![CDATA[ HTTPS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Chengjun.L ]]>
                </dc:creator>
                <pubDate>Mon, 15 Mar 2021 10:06:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/03/dean-pugh-C8NDn4xk9zs-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*8XwjYNPlrj0paEvIjn0Dcw.png" class="kg-image" alt="1*8XwjYNPlrj0paEvIjn0Dcw" width="600" height="400" loading="lazy"></figure><p>如今我们访问的所有网站几乎都受 HTTPS 保护。如果你的网站还没有，<a href="https://developers.google.com/web/fundamentals/security/encrypt-in-transit/why-https">那你应该考虑这么做了</a>。使用 HTTPS 保护服务器安全还意味着你无法从不受 HTTPS 保护的服务器向该服务器发送请求。这给使用本地开发环境的开发人员带来了问题，因为这些本地开发环境都是在 <code>http://localhost</code> 下运行的。</p><p>我在一家创业公司里，我们决定使用 HTTPS 保护我们的 AWS Elastic Load Balancer 端点，以增强安全性。我遇到了一个问题：本地开发环境对服务器的请求被拒绝。</p><p>在谷歌进行快速搜索之后，我发现了几篇类似的文章（<a href="https://devcenter.heroku.com/articles/ssl-certificate-self">1</a>，<a href="https://www.kevinleary.net/self-signed-trusted-certificates-node-js-express-js/">2</a>，<a href="https://blog.praveen.science/securing-your-localhost/">3</a>），其中包含如何在 <code>localhost</code> 实现 HTTPS 的详细说明。即使我认真按这些文章的说明来操作，这些指示似乎也没有起作用。Chrome 总是抛出一个错误：<code>NET::ERR_CERT_COMMON_NAME_INVALID</code>。</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*cQyGAORXHxsrhs5KRRBOgQ.png" class="kg-image" alt="1*cQyGAORXHxsrhs5KRRBOgQ" width="600" height="400" loading="lazy"></figure><h3 id="-"><strong>问题</strong></h3><p>这些文章中的所有详细指示都是对的，但不适用于现在的情况。</p><p>在谷歌进行大量搜索之后，我发现我的本地证书被拒绝的原因是，<code><a href="https://groups.google.com/a/chromium.org/forum/m/#!topic/security-dev/IGT2fLJrAeo">Chrome</a></code><a href="https://groups.google.com/a/chromium.org/forum/m/#!topic/security-dev/IGT2fLJrAeo">已经不再支持证书中的 commonName 匹配</a>。自 2017 年 1 月起，需要使用 <code>subjectAltName</code>这个规则了。</p><h3 id="--1"><strong>解决方案</strong></h3><p>我们将使用 <a href="https://www.openssl.org/" rel="noopener">OpenSSL</a> 生成所有的证书。</p><h4 id="-ssl-"><strong>步骤一：根 SSL 证书</strong></h4><p>第一步是创建根安全套接层（SSL）证书。然后，可以使用此根证书对可能为单个域生成的任何数量的证书进行签名。如果你不熟悉 SSL 生态系统，那么可以阅读 DNSimple 的<a href="https://support.dnsimple.com/articles/what-is-ssl-root-certificate/">这篇文章</a>，里面很好地介绍了根 SSL 证书。</p><p>生成 RSA-2048 密钥，并将其保存到文件 <code>rootCA.key</code> 中。该文件将用作生成根 SSL 证书的密钥。每次使用该特定密钥生成证书时，系统都会提示你输入密码。</p><pre><code class="language-bash">openssl genrsa -des3 -out rootCA.key 2048</code></pre><p>你可以使用生成的密钥来创建新的根 SSL 证书，将其保存到名为 <code>rootCA.pem</code> 的文件中。该证书的有效期为 1,024 天。你可以随时将其更改为你想要的任何天数。系统还会提示你其他可选信息。</p><pre><code class="language-bash">openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.pem</code></pre><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*76xehIse7mPGF094ojiBBw.png" class="kg-image" alt="1*76xehIse7mPGF094ojiBBw" width="600" height="400" loading="lazy"></figure><h4 id="-ssl--1"><strong>步骤二：</strong>信任根 SSL 证书</h4><p>在使用新创建的 Root SSL 证书开始颁发域证书之前，还有一个步骤。你需要告诉 Mac 信任你的根证书，这样它颁发的所有单个证书也将受到信任。</p><p>在 Mac 上打开“钥匙串访问”，然后转到“系统”钥匙串中的“证书”类别，使用文件&gt;导入项目导入 <code>rootCA.pem</code>。双击导入的证书，然后在“信任”部分中将“使用此证书时：”下拉列表更改为“始终信任”。</p><p>如果你到目前为止是正确按照说明进行操作的，则证书在钥匙串访问中的外观应该类似这样：</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*NWwMb0yV9ClHDj87Kug9Ng.png" class="kg-image" alt="1*NWwMb0yV9ClHDj87Kug9Ng" width="600" height="400" loading="lazy"></figure><h4 id="-ssl--2"><strong>步骤三：域 SSL 证书</strong></h4><p>现在可以使用根 SSL 证书来为本地 <code>localhost</code> 开发环境发布证书了。</p><p>创建一个新的 OpenSSL 配置文件 <code>server.csr.cnf</code>，以便在创建证书时可以导入这些设置，而不用在命令行中输入它们。</p><pre><code class="language-bash">[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn

[dn]
C=US
ST=RandomState
L=RandomCity
O=RandomOrganization
OU=RandomOrganizationUnit
emailAddress=hello@example.com
CN = localhost</code></pre><p>创建一个 <code>v3.ext</code> 文件，以便创建一个 <a href="https://en.wikipedia.org/wiki/X.509" rel="noopener">X509 v3 证书</a>。注意这里我们是如何写 &nbsp;<code>subjectAltName</code> 的。</p><pre><code class="language-bash">authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = localhost</code></pre><p>使用 <code>server.csr.cnf</code> 中存储的配置设置为 <code>localhost</code> 创建证书密钥。 该密钥存储在 <code>server.key</code> 中。</p><pre><code class="language-bash">openssl req -new -sha256 -nodes -out server.csr -newkey rsa:2048 -keyout server.key -config &lt;( cat server.csr.cnf )</code></pre><p>通过我们先前创建的根 SSL 证书发出证书签名请求，为 <code>localhost</code> 创建域证书。输出是一个名为 <code>server.crt</code> 的证书文件。</p><pre><code class="language-bash">openssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.crt -days 500 -sha256 -extfile v3.ext</code></pre><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*kulsSyc0-ylsevP5eIlktA.png" class="kg-image" alt="1*kulsSyc0-ylsevP5eIlktA" width="600" height="400" loading="lazy"></figure><h4 id="-ssl--3"><strong>使用你新的 SSL 证书</strong></h4><p>现在，你可以使用 HTTPS 保护本地主机 <code>localhost</code> 了。将 <code>server.key</code> 和 <code>server.crt</code> 文件移动到服务器上的可访问位置，并在启动服务器时将它们包括在内。</p><p>在用 Node.js 编写的 Express 应用中，作如下操作。确保仅针对你的本地环境执行此操作。<strong>不要在生产中使用它。</strong></p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*89r7TnYG49V3zMoUnfOP7Q.png" class="kg-image" alt="1*89r7TnYG49V3zMoUnfOP7Q" width="600" height="400" loading="lazy"></figure><p>希望本教程对你有所帮助。如果你不喜欢自己执行文章里的命令，我已经创建了一组方便的脚本，可以快速运行这些脚本来为你生成证书。你可以在 <a href="https://github.com/dakshshah96/local-cert-generator/">GitHub 仓库</a>中找到更多细节。</p><p>我喜欢帮助其他 Web 开发者。欢迎在 <a href="https://twitter.com/dakshshah96">Twitter</a> 上关注我。如果你有任何建议或反馈，请告诉我。如果你想对我所做的任何工作表示赞赏，无论是博客文章、开源项目还是有趣的推文，<a href="https://www.buymeacoffee.com/dakshshah96">你可以给我买杯咖啡</a>。</p><p>原文：<a href="https://www.freecodecamp.org/news/how-to-get-https-working-on-your-local-development-environment-in-5-minutes-7af615770eec/">How to get HTTPS working on your local development environment in 5 minutes</a>，作者：<a href="https://www.freecodecamp.org/news/author/dakshshah96/">Daksh Shah</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 如何使用 .htaccess 将 HTTP 重定向到 HTTPS ]]>
                </title>
                <description>
                    <![CDATA[ Chrome 和 Firefox 已开始在没有 SSL 证书 [https://www.instantssl.com/ssl.html] 的网站上显示不安全警告。没有 SSL，你的网站将对访问者显示不安全。因此，有必要使用 SSL 加密连接，保障安全性、可访问性 或 PCI 合规性。从 HTTP 重定向到 HTTPS 非常重要。 什么是 SSL SSL（安全套接层）是一种标准安全协议，用于在在线通信中的 Web 服务器和浏览器之间建立加密链接。 SSL 技术的使用可确保在 Web 服务器和浏览器之间传输的所有数据均保持加密状态。 SSL 证书是创建 SSL 连接所必需的。当你选择在 Web 服务器上激活 SSL 时，你需要提供有关网站和公司身份的所有详细信息。然后，将创建两个加密密钥——一个私有密钥和一个公共密钥。 了解更多：为什么 SSL 很关键？ [https://www.sslrenewals.com/blog/why-is-ssl-important-benefits-of-using-ssl-certificate] 为了强制你的流量使用 HTTPS，请编辑 .ht ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/how-to-redirect-http-to-https-using-htaccess/</link>
                <guid isPermaLink="false">6007a9675f61e30501b5be19</guid>
                
                    <category>
                        <![CDATA[ HTTPS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Chengjun.L ]]>
                </dc:creator>
                <pubDate>Tue, 19 Jan 2021 11:00:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/01/photo-1483213097419-365e22f0f258.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Chrome 和 Firefox 已开始在没有 <a href="https://www.instantssl.com/ssl.html">SSL 证书</a>的网站上显示不安全警告。没有 SSL，你的网站将对访问者显示不安全。因此，有必要使用 SSL 加密连接，保障安全性、可访问性 或 PCI 合规性。从 HTTP 重定向到 HTTPS 非常重要。</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/0*wUTFJrRSM2vh1H7v.jpg" class="kg-image" alt="0*wUTFJrRSM2vh1H7v" width="800" height="289" loading="lazy"></figure><h3 id="-ssl"><strong><strong>什么是</strong> <strong>SSL</strong></strong></h3><p>SSL（安全套接层）是一种标准安全协议，用于在在线通信中的 Web 服务器和浏览器之间建立加密链接。</p><p>SSL 技术的使用可确保在 Web 服务器和浏览器之间传输的所有数据均保持加密状态。</p><p><strong>SSL 证书</strong>是创建 SSL 连接所必需的。当你选择在 Web 服务器上激活 SSL 时，你需要提供有关网站和公司身份的所有详细信息。然后，将创建两个加密密钥——一个私有密钥和一个公共密钥。</p><p><em><a href="https://www.sslrenewals.com/blog/why-is-ssl-important-benefits-of-using-ssl-certificate"><em>了解更多</em>：为什么 SSL 很关键？</a></em></p><p>为了强制你的流量使用 HTTPS，请编辑 <strong>.htaccess</strong> 文件中的代码。</p><p>在开始讨论将 HTTP 重定向到 HTTPS 之前，这里我们讨论编辑 .htaccess 文件的方法。如果你已经知道了，可以跳到重定向步骤。</p><h3 id="-htaccess-"><strong><strong>编辑 .htaccess 文件</strong></strong></h3><p>.htaccess 文件中有些指令，它们告诉服务器在某些情况下如何操作，并直接影响网站的功能。.htaccess 文件中的常见指令包括：</p><ul><li>Redirects</li><li>Rewriting URLs</li></ul><p><strong>编辑 .htaccess 文件的方法：</strong></p><ul><li>在计算机上编辑文件，然后使用 FTP 将其上传到服务器</li><li>在 FTP 程序中使用“编辑”模式，该模式允许你远程编辑文件</li><li>使用文本编辑器和 SSH 编辑文件</li><li>使用 <strong>cPanel</strong> 中的文件管理器来编辑文件</li></ul><h3 id="-cpanel-htaccess"><strong><strong>在</strong> <strong>cPanel</strong> 文件管理器中<strong>编辑 .htaccess</strong></strong></h3><p><strong>注意：</strong>备份你的网站，以防出现问题。</p><p>1、登录到 cPanel</p><p>2、访问文件&gt;文件管理器&gt;文档根目录</p><p>3、现在选择你要访问的域名</p><p>4、选中“显示隐藏文件（dot 文件）”</p><p>5、点击“开始”</p><p>6、打开新的选项卡或窗口后，查找 .htaccess 文件</p><p>7、右键单击 .htaccess 文件，然后在菜单上单击“代码编辑”</p><p>8、可能会弹出一个对话框，询问有关编码的信息，单击“编辑”按钮继续</p><p>9、编辑文件</p><p>10、完成后“保存更改”</p><p>11、测试你的网站，以确保其正确完成，如果出现错误，请还原到以前的版本，然后重试。</p><p>12、完成后，单击“关闭”以关闭窗口</p><h3 id="-http-https"><strong><strong>重定向 HTTP 到 HTTPS</strong></strong></h3><h4 id="1-"><strong><strong>1</strong>、重定向所有流量</strong></h4><p>如果你的 .htaccess 中已有代码，请添加以下代码：</p><pre><code>RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://www.yourdomain.com/$1 [R,L]</code></pre><h4 id="2-"><strong><strong>2</strong>、重定向一个特定的域名</strong></h4><p>要重定向特定域名以使用 HTTPS，请添加以下代码：</p><pre><code>RewriteEngine On
RewriteCond %{HTTP_HOST} ^yourdomain\.com [NC]
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://www.yourdomain.com/$1 [R,L]</code></pre><h4 id="3-"><strong><strong>3</strong>、重定向一个特定的文件夹</strong></h4><p>要对一个特定的文件夹重定向到 HTTPS，请添加以下代码：</p><pre><code>RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteCond %{REQUEST_URI} folder
RewriteRule ^(.*)$ https://www.yourdomain.com/folder/$1 [R,L]</code></pre><p>注意：如有需要，请用你的实际域名替换“<em><em><code>yourdomain</code></em></em>”。另外，对于文件夹，请用实际的文件夹名称替换 <em><em><code>/folder</code></em></em>。</p><p>你觉得这篇文章有帮助吗？欢迎分享本文，以帮助更多人使用 HTTPS。</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/0*P6EKtlMMzyIXNRMw.png" class="kg-image" alt="0*P6EKtlMMzyIXNRMw" width="670" height="240" loading="lazy"></figure><p><br>原文：<a href="https://www.freecodecamp.org/news/how-to-redirect-http-to-https-using-htaccess/">How to redirect HTTP to HTTPS Using .htaccess</a>，作者：<a href="https://www.freecodecamp.org/news/author/bolajiayodeji/">Bolaji Ayodeji</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 通俗易懂的 HTTPS（二） ]]>
                </title>
                <description>
                    <![CDATA[ 密码学有什么帮助？ 在本节中，你将学习一种保护数据安全的方法，即创建自己的加密密钥并在服务器和客户机上使用它们。虽然这不是你的最后一步，但它将帮助你为学会构建Python HTTPS应用程序奠定坚实的基础。 了解密码学基础知识 密码学是一种保护通信免受窃听或攻击的方法。另一种说法是，你获取正常的信息（称为明文），然后把它转换成加密的文本（称为密文）。 密码学一开始可能很吓人，但基本概念是很容易理解的。事实上，你以前可能已经练习过密码学。如果你曾经和你的朋友有过一种秘密语言，并在课堂上用它来传递笔记，那么你就已经练习过密码学。（如果你还没做到，别担心，你即将做到。） 不管什么理由，现在你需要把字符串fluffy tail 转换成一些难以理解的东西。一种方法是将某些字符映射到不同的字符上，还有一种有效的方法是将字母向后移动一个位置，这种做法看起来是这样的： 此图显示如何从原始字母表转换为新字母表并返回。所以，如果你的信息是ABC，那么实际上发送的信息将会是ZAB。如果把这个应用到fluffy tail 上，且长度不变，就得到ekteex szhk，虽然并不完美，但任何人看到都会觉得 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/what-is-https-part-two/</link>
                <guid isPermaLink="false">5e3d5f21ca1efa04e196b480</guid>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTTPS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ qiwsir ]]>
                </dc:creator>
                <pubDate>Fri, 07 Feb 2020 13:15:07 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/04/photo-1580944026788-06ff362ecad1.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <h2 id="-"><strong>密码学有什么帮助？</strong></h2><p>在本节中，你将学习一种保护数据安全的方法，即创建自己的加密密钥并在服务器和客户机上使用它们。虽然这不是你的最后一步，但它将帮助你为学会构建Python HTTPS应用程序奠定坚实的基础。</p><h3 id="--1"><strong>了解密码学基础知识</strong></h3><p>密码学是一种保护通信免受窃听或攻击的方法。另一种说法是，你获取正常的信息（称为明文），然后把它转换成加密的文本（称为密文）。</p><p>密码学一开始可能很吓人，但基本概念是很容易理解的。事实上，你以前可能已经练习过密码学。如果你曾经和你的朋友有过一种秘密语言，并在课堂上用它来传递笔记，那么你就已经练习过密码学。（如果你还没做到，别担心，你即将做到。）</p><p>不管什么理由，现在你需要把字符串<code>fluffy tail</code>转换成一些难以理解的东西。一种方法是将某些字符映射到不同的字符上，还有一种有效的方法是将字母向后移动一个位置，这种做法看起来是这样的：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/02/image-15.png" class="kg-image" alt="image-15" width="428" height="142" loading="lazy"></figure><p>此图显示如何从原始字母表转换为新字母表并返回。所以，如果你的信息是<code>ABC</code>，那么实际上发送的信息将会是<code>ZAB</code>。如果把这个应用到<code>fluffy tail</code>上，且长度不变，就得到<code>ekteex szhk</code>，虽然并不完美，但任何人看到都会觉得它是胡言乱语。</p><p>祝贺你！你已经创建了在密码学中称为密码的东西，它描述了如何将明文转换为密文并返回。在这种情况下，你的密码是用英语描述的。这种特殊类型的密码称为替换密码。基本上，这与Enigma机器（https://en.wikipedia.org/wiki/Enigma_Machine）中使用的密码类型相同，只是简单得多。</p><p>现在，如果你想把信息传给秘密松鼠，那么你首先需要告诉它们要移动多少个字母，然后把编码的信息发给它们。在Python中，这可能类似于以下内容：</p><pre><code>CIPHER = {"a": "z", "A": "Z", "b": "a"} # And so on

def encrypt(plaintext: str):
    return "".join(CIPHER.get(letter, letter) for letter in plaintext)</code></pre><p>在这里，你创建了一个名为<code>encrypt()</code>的函数，它将获取明文并将其转换为密文。想象一下，你有一本字典<code>CIPHER</code>，它把所有的字符都标出来了。类似地，你可以创建一个<code>decrypt()</code>：</p><pre><code>DECIPHER = {v: k for k, v in CIPHER.items()}

def decrypt(ciphertext: str):
    return "".join(DECIPHER.get(letter, letter) for letter in ciphertext)</code></pre><p>此函数与<code>encrypt()</code>相反，它将接受密文并将其转换为明文。在这种形式的密码中，你有一个特殊的密钥，用户需要知道该密钥才能对消息进行加密和解密。对于上面的示例，该密钥是<code>1</code>。也就是说，密码指示你应该将每个字母移回一个字符。密钥对于保密非常重要，因为任何拥有密钥的人都可以轻松地解密你的信息。</p><p>注意：虽然你可以用它来加密，但这仍然不是很安全。这个密码使用频率分析很容易破解，并且对秘密松鼠来说太原始了。</p><p>在现代社会，密码学要先进得多，它依赖于复杂的数学理论和计算机科学来保证安全。虽然这些密码背后的数学不在本文的讨论范围内，但基本概念是相同的。你有一个密码，它描述了如何获取明文并将其转换为密文。</p><p>你的替换密码和现代密码的唯一真正区别是：现代密码在数学上被证明是无法被窃听者破解的。现在，让我们看看如何使用你的新密码。</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://chinese.freecodecamp.org/news/content/images/2020/02/image-17.png" class="kg-image" alt="image-17" width="800" height="884" loading="lazy"><figcaption>预计 2020 年 3 月发行<span class="-mobiledoc-kit__atom">‌‌</span></figcaption></figure><h3 id="-python-https-"><strong>在Python HTTPS应用中使用密码学</strong></h3><p>幸运的是，你不必成为数学或计算机科学的专家就可以使用密码学。Python有一个secrets模块，可以帮助你生成密码安全的随机数据。在本文中，你将了解一个名为<code>cryptography</code>的Python库，可以用<code>pip</code>安装它：</p><pre><code>$ pip install cryptography</code></pre><p>安装了<code>cryptography</code>之后，你现在可以使用<code>Fernet</code>方法以数学上安全的方式加密和解密。</p><p>记得你密码里的密钥是1。同样，你需要创建一个密钥，以便让<code>Fernet</code>正常运行：</p><pre><code>&gt;&gt;&gt; from cryptography.fernet import Fernet
&gt;&gt;&gt; key = Fernet.generate_key()
&gt;&gt;&gt; key
b'8jtTR9QcD-k3RO9Pcd5ePgmTu_itJQt9WKQPzqjrcoM='</code></pre><p>在这段代码中，导入了<code>Fernet</code>并生成了一个密钥。密钥只是一个bytes对象，但是保持密钥的机密性和安全性是非常重要的。就像上面的替换示例一样，任何具有此密钥的人都可以轻松地解密你的信息。</p><p>注意：在现实生活中，你会把这个密钥保管得很安全。在这些例子中，查看密钥是有帮助的。但这是一个糟糕的做法，特别是如果你在公共网站上发布它！换言之，不要使用你在上面看到的确切的密钥来获得你想要的安全性。</p><p>这个密钥的运行方式与前面的密钥很相似，用它可以将明文转换为密文，并且能够解密返回明文。现在是有趣的部分了！你可以加密如下信息：</p><pre><code>&gt;&gt;&gt; my_cipher = Fernet(key)
&gt;&gt;&gt; ciphertext = my_cipher.encrypt(b"fluffy tail")
&gt;&gt;&gt; ciphertext
b'gAAAAABdlW033LxsrnmA2P0WzaS-wk1UKXA1IdyDpmHcV6yrE7H_ApmSK8KpCW-6jaODFaeTeDRKJMMsa_526koApx1suJ4_dQ=='</code></pre><p>在这段代码中，创建了一个名为<code>my_cipher</code>的Fernet对象，然后可以使用它来加密信息。注意，你的秘密信息<code>fluffy tail</code>必须是bytes对象才能对其进行加密。加密后，可以看到“密文”是一个长字节流。</p><p>多亏了Fernet，这个密文没有密钥就不能被操作或阅读！这种加密要求服务器和客户端都有权访问密钥。当双方都需要相同的密钥时，这称为对称加密。在下一节中，你将看到如何使用这种对称加密来保证数据的安全。</p><h3 id="--2"><strong>确保数据安全</strong></h3><p>现在，你已经了解了Python中密码学的一些基础知识，可以将这些知识应用到你的服务器上。创建名为<code>symmetric_server.py</code>的新文件：</p><pre><code># symmetric_server.py
import os
from flask import Flask
from cryptography.fernet import Fernet

SECRET_KEY = os.environb[b"SECRET_KEY"]
SECRET_MESSAGE = b"fluffy tail"
app = Flask(__name__)

my_cipher = Fernet(SECRET_KEY)

@app.route("/")
def get_secret_message():
    return my_cipher.encrypt(SECRET_MESSAGE)</code></pre><p>此代码将原始服务器代码与上一节中使用的<code>Fernet</code>对象组合在一起。现在使用<code>os.environb</code>将密钥作为bytes对象从环境变量中读取。扫清了服务器方面的障碍之后，你现在可以专注于客户端。将以下内容粘贴到<code>symmetric_client.py</code>中：</p><pre><code># symmetric_client.py
import os
import requests
from cryptography.fernet import Fernet

SECRET_KEY = os.environb[b"SECRET_KEY"]
my_cipher = Fernet(SECRET_KEY)

def get_secret_message():
    response = requests.get("http://127.0.0.1:5683")

    decrypted_message = my_cipher.decrypt(response.content)
    print(f"The codeword is: {decrypted_message}")

if __name__ == "__main__":
    get_secret_message()</code></pre><p>这是修改后的代码，用于把你的早期客户端与<code>Fernet</code>加密机制相结合。<code>get_secret_message()</code>执行以下操作：</p><ul><li>向服务器发出请求。</li><li>从响应中获取原始字节。</li><li>尝试解密原始字节。</li><li>打印解密的信息。</li></ul><p>如果同时运行服务器和客户端，你将看到正在成功地加密和解密你的秘密信息：</p><pre><code>$ uwsgi --http-socket 127.0.0.1:5683 \
    --env SECRET_KEY="8jtTR9QcD-k3RO9Pcd5ePgmTu_itJQt9WKQPzqjrcoM=" \
    --mount /=symmetric_server:app</code></pre><p>在此调试中，你将再次在端口5683上启动服务器。这一次，传入的SECRET_KEY 必须至少是长度为32的base64编码字符串。重新启动服务器后，你现在可以查询它：</p><pre><code>$ SECRET_KEY="8jtTR9QcD-k3RO9Pcd5ePgmTu_itJQt9WKQPzqjrcoM=" python symmetric_client.py
The secret message is: b'fluffy tail'</code></pre><p>哇！你已经实现加密和解密了。如果尝试使用无效的SECRET_KEY运行此操作，则会出现错误：</p><pre><code>$ SECRET_KEY="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" python symmetric_client.py
Traceback (most recent call last):
  File ".../cryptography/fernet.py", line 104, in _verify_signature
    h.verify(data[-32:])
  File ".../cryptography/hazmat/primitives/hmac.py", line 66, in verify
    ctx.verify(signature)
  File ".../cryptography/hazmat/backends/openssl/hmac.py", line 74, in verify
    raise InvalidSignature("Signature did not match digest.")
cryptography.exceptions.InvalidSignature: Signature did not match digest.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "symmetric_client.py", line 16, in &lt;module&gt;
    get_secret_message()
  File "symmetric_client.py", line 11, in get_secret_message
    decrypted_message = my_cipher.decrypt(response.content)
  File ".../cryptography/fernet.py", line 75, in decrypt
    return self._decrypt_data(data, timestamp, ttl)
  File ".../cryptography/fernet.py", line 117, in _decrypt_data
    self._verify_signature(data)
  File ".../cryptography/fernet.py", line 106, in _verify_signature
    raise InvalidToken
cryptography.fernet.InvalidToken</code></pre><p>所以，你知道加密和解密是有效的。但它安全吗？是的。为了证明这一点，你可以回到Wireshark，使用与以前相同的过滤器开始新的捕获。完成捕获设置后，再次运行客户端代码：</p><pre><code>$ SECRET_KEY="8jtTR9QcD-k3RO9Pcd5ePgmTu_itJQt9WKQPzqjrcoM=" python symmetric_client.py
The secret message is: b'fluffy tail'</code></pre><p>你已经成功地发出了另一个HTTP请求和响应，并且再次在Wireshark中看到这些信息。由于加密信息只在响应中传输，你可以单击该信息查看数据：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/02/image-16.png" class="kg-image" alt="image-16" width="1080" height="726" loading="lazy"></figure><p>在图片的中间一行，可以看到实际传输的数据：</p><pre><code>gAAAAABdlXSesekh9LYGDpZE4jkxm4Ai6rZQg2iHaxyDXkPWz1O74AB37V_a4vabF13fEr4kwmCe98Wlr8Zo1XNm-WjAVtSgFQ==</code></pre><p>棒极了！这意味着数据是加密的，窃听者不知道信息内容实际上是什么。不仅如此，这也意味着他们可能会花费大量的时间试图暴力破解这些数据，而且他们几乎永远不会成功。</p><p>你的数据是安全的！但是等一下——以前使用Python HTTPS应用时，不需要知道任何关于钥匙的事情。这是因为HTTPS不专门使用对称加密。事实证明，分享秘密是个难题。</p><p>要证明这个概念，请在浏览器中输入<code>http://127.0.0.1:5683</code>，你将看到加密的响应文本。这是因为你的浏览器对你的密钥一无所知。那么Python HTTPS应用程序到底是如何工作的呢？这就是非对称加密发挥作用的地方。</p><h3 id="--3"><strong>如何共享密钥？</strong></h3><p>在上一节中，你了解了如何使用对称加密来保证数据在Internet上的安全。尽管对称加密是安全的，但它并不是Python HTTPS应用用来保证数据安全的唯一加密技术。对称加密引入了一些不易解决的基本问题。</p><p>注意：记住，对称加密要求在客户端和服务器之间有一个共享密钥。不幸的是，安全性的工作强度取决于最弱的链接，而在对称加密中，弱链接尤其具有灾难性。一旦一个人泄露了密钥，那么每个密钥都会泄露。可以肯定的是，任何安全系统在某个时候都会受到损害。</p><p>那么，你怎么改变密钥？如果你只有一个服务器和一个客户端，这可能是一个快速的任务。然而，随着客户端和服务器的增多，为了有效地更改密钥和保护信息，需要进行越来越多的协调。</p><p>而且，你每次都要选择一个新的加密方式。在上面的示例中，你看到一个随机生成的密钥，几乎不可能试着让人们记住那个密钥。随着客户端和服务器数量的增长，可能会使用更容易记住和猜测的密钥。</p><p>如果处理好了更改密钥的问题，那么还有一个问题要解决，如何分享你的初始密钥？在秘密松鼠示例中，你通过对每个成员进行物理访问来解决了这个问题，可以亲自把密钥告诉每个成员，让他们保守秘密，但要记住，有人会是最薄弱的环节。</p><p>现在，假设你从另一个物理位置向秘密松鼠会添加一个成员，如何与这个会员分享这个秘密？每次更改密钥时，你都让他们搭飞机去找你吗？如果你能把密钥放在你的服务器上并自动共享，那就太好了。不幸的是，这会挫败加密的全部目的，因为任何人都可以得到密钥！</p><p>当然，你可以给每个人一个初始的主密钥来获取秘密信息，但现在你遇到的问题是以前的两倍。如果你为之头痛，别担心！你不是唯一一个。</p><p>你需要的是两个从未交流过的人有一个共同的秘密。听起来不可能，对吧？幸运的是，有三个人：拉尔夫·梅克尔、惠特菲尔德·迪菲和马丁·赫尔曼，他们支持你，他们证明了公钥加密（也就是所谓的非对称加密）是可能的。</p><p>注：虽然惠特菲尔德·迪菲和马丁·赫尔曼被广泛认为是第一个发现这一计划的人，但据1997年的披露，在GCHQ工作的三人：詹姆斯·H·埃利斯、克利福德·考克斯和马尔科姆·J·威廉森早在七年前就展示了这种功能！</p><p>非对称加密允许两个从未有过通信的用户共享一个共同的秘密。理解基本原理的最简单方法之一是使用颜色类比。假设你有以下场景：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/02/image-18.png" class="kg-image" alt="image-18" width="761" height="451" loading="lazy"></figure><p>在这个图表中，你试图与一个你从未见过的“秘密松鼠”成员交流，但间谍可以看到你发送的所有信息。你知道对称加密并且想使用它，但是首先需要共享一个密钥。幸运的是，你们俩都有私钥。不幸的是，你不能发送你的私钥，因为间谍会看到它。那你怎么办？</p><p>你需要做的第一件事就是同意使用你的伙伴的颜色，比如黄色：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/02/image-19.png" class="kg-image" alt="image-19" width="781" height="481" loading="lazy"></figure><p>注意这里间谍可以看到共享的颜色，你和秘密松鼠也可以。共享颜色实际上是公开的。现在，你和秘密松鼠将你的私钥与共享颜色结合起来：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/02/image-20.png" class="kg-image" alt="image-20" width="781" height="561" loading="lazy"></figure><p>你的颜色组合成绿色，而秘密松鼠的颜色组合成橙色。你们两个都使用了共享颜色，现在你们需要彼此共享组合的颜色：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/02/image-21.png" class="kg-image" alt="image-21" width="782" height="451" loading="lazy"></figure><p>你现在有了你的私钥和秘密松鼠的颜色组合。同样地，秘密松鼠有他们的私钥和你的组合颜色。你和秘密松鼠很快就把你们的颜色组合起来了。</p><p>然而，间谍只有这两种颜色。要想弄清楚你的原色是非常困难的，即使给定了最初的共享颜色。间谍得去商店买很多不同的蓝颜料来试试。即使这样，也很难知道他们在组合后是否看到了具有正确深浅度的绿色！简而言之，你的私钥仍然是私钥。</p><p>但是你和那个“秘密松鼠”成员呢？你们仍然没有一个共同的秘密！这是你的私钥重新派上用场的地方。如果你把你的私钥和你从秘密松鼠那里得到的颜色组合在一起，那么你俩最终会得到相同的颜色：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/02/image-22.png" class="kg-image" alt="image-22" width="761" height="481" loading="lazy"></figure><p>现在，你和这个“秘密松鼠”成员有着相同的秘密颜色。你现在已经成功地和一个完全陌生的人分享了一个安全的秘密。这对于公钥密码的工作方式来说是惊人的精确。这个事件序列还有另一个通用名称：Diffie-Hellman密钥交换。密钥交换由以下部分组成：</p><ul><li>私钥是示例中的私用颜色。</li><li>公钥是你共享的组合颜色。</li></ul><p>私钥是你始终保持私有的东西，而公钥可以与任何人共享。这些概念直接映射到Python HTTPS应用程序的现实世界。既然服务器和客户端有了一个共享的秘密，你可以使用你的“老伙计”对称加密来对所有信息进行加密！</p><p>注意：公钥密码术也依赖于一些数学知识来进行颜色混合。Diffie-Hellman密钥交换的维基百科词条有很好的解释，但是深入的解释不在本文的范围之内。</p><p>当你通过安全网站（如本网站）进行通信时，你的浏览器和服务器使用这些相同的原则设置安全通信：</p><ul><li>浏览器从服务器请求信息。</li><li>浏览器和服务器交换公钥。</li><li>浏览器和服务器生成共享私钥。</li><li>浏览器和服务器使用此共享密钥通过对称加密对消息进行加密和解密。</li></ul><p>幸运的是，你不需要实现这些细节。有许多内置库和第三方库可以帮助你保持客户端和服务器通信的安全。</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 通俗易懂的HTTPS（一） ]]>
                </title>
                <description>
                    <![CDATA[ 你有没有想过为什么你可以通过互联网发送你的信用卡信息？你可能已经注意到了浏览器地址栏中的https:// ，但它是什么？它如何保证你的信息安全？或者你可能想要创建一个Python HTTPS应用程序，但你并不完全确定这意味着什么。如何确保你的web应用是安全的？ 你可能会惊讶地发现，不用成为安全专家，也能能回答这些问题！在本文中，你就能得到相关的知识，这些知识组合在一起，可确保网络通信安全。你将看到一些具体示例，这些示例展示了Python HTTPS如何保证信息安全。 > 译者注：HTTPS是以安全为目标的HTTP通道，已被广泛用于大多数网络应用。本系列分三部分发布《通俗易懂的HTTPS》，并以Python语言实现HTTPS方案。 在本文中，你将学到：  * 监视和分析网络流量  * 应用加密技术保证数据安全  * 描述公钥（PKI）的核心概念  * 创建你自己的证书颁发机构  * 构建Python HTTPS应用程序  * 识别常见的Python HTTPS警告和错误 什么是HTTP？ 在深入了解HTTPS及其在Python中的使用之前，了解它的上一代HTTP是很重要的。HT ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/what-is-https-part-one/</link>
                <guid isPermaLink="false">5e32aa25ca1efa04e196af93</guid>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTTPS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ qiwsir ]]>
                </dc:creator>
                <pubDate>Thu, 30 Jan 2020 10:13:53 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/04/photo-1580365311133-166ddb4864cf.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>你有没有想过为什么你可以通过互联网发送你的信用卡信息？你可能已经注意到了浏览器地址栏中的https:// ，但它是什么？它如何保证你的信息安全？或者你可能想要创建一个Python HTTPS应用程序，但你并不完全确定这意味着什么。如何确保你的web应用是安全的？</p><p>你可能会惊讶地发现，不用成为安全专家，也能能回答这些问题！在本文中，你就能得到相关的知识，这些知识组合在一起，可确保网络通信安全。你将看到一些具体示例，这些示例展示了Python HTTPS如何保证信息安全。</p><blockquote>译者注：HTTPS是以安全为目标的HTTP通道，已被广泛用于大多数网络应用。本系列分三部分发布《通俗易懂的HTTPS》，并以Python语言实现HTTPS方案。</blockquote><p>在本文中，你将学到：</p><ul><li>监视和分析网络流量</li><li>应用加密技术保证数据安全</li><li>描述公钥（PKI）的核心概念</li><li>创建你自己的证书颁发机构</li><li>构建Python HTTPS应用程序</li><li>识别常见的Python HTTPS警告和错误</li></ul><h2 id="-http-"><strong>什么是HTTP？</strong></h2><p>在深入了解HTTPS及其在Python中的使用之前，了解它的上一代HTTP是很重要的。HTTP是HyperText Transfer Protocol（超文本传输协议）的缩写，它支持浏览网站时的通信。更具体地说，HTTP是用户端（如web浏览器）与web服务器（如itdiffer.com）通信的方式。下面是HTTP通信的简化图：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/01/image-30.png" class="kg-image" alt="image-30" width="791" height="292" loading="lazy"></figure><p>这个图表显示了计算机与服务器通信的流程，下面对每一步给予分解说明：</p><ol><li>告诉浏览器访问http://qiwsir.github.io/。</li><li>你的设备和服务器建立了TCP连接。</li><li>浏览器向服务器发送HTTP请求。</li><li>服务器接收HTTP请求并对其进行解析。</li><li>服务器借助HTTP响应产生反应。</li><li>计算机接收、解析并显示响应。</li></ol><p>这个分解说明包含了HTTP的基本知识，向服务器发出请求，服务器返回响应。虽然HTTP不需要TCP，但它确实需要可靠的低级协议。在实践中，几乎总是基于IP实现TCP(尽管谷歌试图创建一个替代品)。</p><p>就协议而言，HTTP是最简单的协议之一。它的设计目的是通过互联网发送内容，如HTML、视频、图像等，这都是通过HTTP请求和响应完成的。HTTP请求包含以下元素：</p><ul><li>请求方法：描述客户端要执行操作的方法，静态内容的方法通常是GET，此外还有其他可用的方法，如POST、HEAD和DELETE。</li><li>路径：向服务器指示要请求的网页。例如，此页面的路径是/python-https。</li><li>版本：HTTP的版本，如1.0、1.1或2.0。最常见的可能是1.1。</li><li>headers：描述服务器的其他信息。</li><li>body：向服务器提供来自客户端的信息。虽然这个字段不是必需的，但是某些方法要求有提交的内容，比如POST。</li></ul><p>这些是浏览器用于与服务器通信的内容，服务器借助HTTP响应产生反应，并返回如下信息：</p><ul><li>HTTP版本，该版本通常与请求的版本相同。</li><li>状态代码：指示是否已成功完成了请求。状态代码有很多。</li><li>状态消息：提供有助于描述状态代码的可读消息。</li><li>headers：允许服务器使用关于请求的附加元数据进行响应。</li><li>body：承载着内容。从技术上讲，这是可选的，但它通常包含一个有用的资源。</li></ul><p>这些是HTTP的组成。</p><h2 id="-https-"><strong>什么是HTTPS？</strong></h2><p>现在你对HTTP有了详细了解，那么，什么是HTTPS？好消息是，你已经知道了！HTTPS，即Hyper Text Transfer Protocol over SecureSocket Layer，超文本传输安全协议。从根本上说，HTTPS与HTTP是相同的协议，但它也意味着通信是安全的。</p><p>HTTPS不会重写它所构建的任何HTTP基础，相反，HTTPS由通过加密连接发送的常规HTTP组成。通常，这种加密连接由TLS或SSL提供，它们是在信息通过网络发送之前对其进行加密的协议。</p><p>注意：TLS和SSL是非常相似的协议，尽管SSL正在退出，TLS将取代它。这些协议中的差异不在本文的范围内。只要知道TLS是SSL的更新、更好的版本就足够了。</p><p>那么，为什么要有HTTP和HTTPS两种呢？为什么不把加密引入HTTP协议本身呢？答案是可移植性。保护通信安全是一个重要而困难的问题，但HTTP只是许多需要安全性的协议之一。在网络上，除了网页访问之外，还有其他的许多应用：</p><ul><li>E-mail</li><li>即时通讯</li><li>VoIP</li></ul><p>每项应用都有专门的协议，如果每个协议都必须创建自己的安全机制，那么这个世界就会变得更加不安全，也会更加混乱。TLS是上述协议中常用的一种安全通信方法。</p><p>在下文中，你将学习到的几乎所有内容都不仅仅适用于Python HTTPS应用，此外，还将学习安全通信的基础知识，以及它如何具体应用于HTTPS。</p><h2 id="-https--1"><strong>为什么HTTPS很重要？</strong></h2><p>通信安全对于提供安全的在线环境至关重要。随着包括银行和医疗站点在内的越来越多的网络应用，对于开发人员来说，创建Python HTTPS应用变得越来越重要。同样，HTTPS只是TLS或SSL上的HTTP，TLS的设计是为了保护隐私不被窃听，它还可以提供客户端和服务器的身份验证。</p><p>在本文中，你将通过执行以下操作深入探讨这些概念：</p><ul><li>创建Python HTTPS服务器</li><li>与Python HTTPS服务器通信</li><li>捕获这些通信</li><li>分析这些消息</li></ul><p>我们开始吧！</p><h3 id="-"><strong>创建示例</strong></h3><p>假设你是一个叫做秘密松鼠的酷Python俱乐部的领导，松鼠，作为机密，需要以加密信息的方式发布给会议。作为领导，你要选择发布的加密信息，每次会议都会更改这个信息。不过，有时候，你很难在会前和所有会员见面，告诉他们此信息！你决定设置一个秘密服务器，成员可以在其中只能看到发给他们的加密信息。</p><p>You’ve followed some tutorials on Real Python and decide to use some dependencies you know:</p><p>你已经学习了一些关于真正Python的知识（<strong>如果还没有学习，推荐《Python大学实用教程》（电子工业出版社）</strong>），并安装如下模块：</p><ul><li>用于构建web应用程序的Flask</li><li>作为生产服务器的uWSGI</li><li>向服务器发起请求的requests</li></ul><p>要安装所有这些，可以使用<code>pip</code>：</p><pre><code>$ pip install flask uwsgi requests</code></pre><p>安装后，就可以开始编写应用程序了。创建名为<code>server.py</code>的文件，并在其中编写Flask应用：</p><pre><code># server.py
from flask import Flask

SECRET_MESSAGE = "fluffy tail"
app = Flask(__name__)

@app.route("/")
def get_secret_message():
    return SECRET_MESSAGE</code></pre><p>每当有人访问服务器的<code>/</code>路径时，这个Flask应用程序将显示<code>SECRET_MESSAGE</code>的内容。这样一来，就可以在秘密服务器上部署应用程序并运行它：</p><pre><code>$ uwsgi --http-socket 127.0.0.1:5683 --mount /=server:app</code></pre><p>此命令旨在启动的服务器上使用上面的Flask应用，所使用的端口有点奇怪（5683），因为你不希望别人能找到它，为自己的“鬼鬼祟祟”感到庆幸！可以通过访问浏览器访问<code>http://localhost:5683</code>来确认它是否正常工作。</p><p>因为秘密松鼠俱乐部中的每个人都认识Python，所以你决定帮助他们编写一个名为client.py的脚本，以便让他们获取加密信息：</p><pre><code># client.py
import os
import requests

def get_secret_message():
    url = os.environ["SECRET_URL"]
    response = requests.get(url)
    print(f"The secret message is: {response.text}")

if __name__ == "__main__":
    get_secret_message()</code></pre><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/01/image-31.png" class="kg-image" alt="image-31" width="1080" height="634" loading="lazy"></figure><p>只要设置了<code>SECRET_URL</code>环境变量，此代码就会打印出秘密消息。在本例中，<code>SECRET_URL</code>是<code>127.0.0.1:5683</code>。所以，你的计划是给每个俱乐部成员一个秘密的网址，告诉他们要保密和安全。</p><p>虽然这可能看起来不错，但这样做还不够！事实上，即使你在这个网站上输入用户名和密码，它仍然是不安全的。甚至你的团队设法保证了URL的安全，你的秘密消息也还不安全。为了说明为什么你需要了解一些有关监视网络流量的信息，你需要使用一个名为Wireshark的工具。</p><h3 id="setting-up-wireshark"><strong>Setting Up Wireshark</strong></h3><h3 id="-wireshark"><strong>设置Wireshark</strong></h3><p>Wireshark是一个应用广泛的网络和协议分析工具，这它可以帮助你了解网络连接上发生的事情。安装和设置Wireshark对于本文是可选的，但是如果你想继续学习，请安装和使用它。下载页提供了几个安装程序：</p><ul><li>macOS 10.12及更高版本</li><li>64位Windows安装程序</li><li>32位Windows安装程序</li></ul><p>如果你使用的是Windows或Mac，应该能够下载适当的安装程序并按照提示进行操作。最后，你应该有一个正在运行的Wireshark。</p><p>如果你是在一个基于Debian的Linux环境中，安装就会有点困难，但仍然是可能的。可以使用以下命令安装Wireshark：</p><pre><code>$ sudo add-apt-repository ppa:wireshark-dev/stable
$ sudo apt-get update
$ sudo apt-get install wireshark
$ sudo wireshark</code></pre><p>启动Wireshark之后，可以看到如下界面：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/01/image-32.png" class="kg-image" alt="image-32" width="1080" height="634" loading="lazy"></figure><p>随着Wireshark的运行，是时候分析一些流量了！</p><h3 id="--1"><strong>看呀，你的数据多么不安全</strong></h3><p>当前客户端和服务器的运行方式是非常不安全的。HTTP发送的所有东西，任何人都可以清楚地看到。这意味着，即使某人没有你的<code>SECRET_URL</code>，他仍然可以看到你所做的一切，只要他可以监视你和服务器之间的任何设备上的流量。</p><p>这对你来说应该比较可怕。毕竟，你不想别人出现在你的秘密松鼠会议上！下面证明这种情况是真实发生的。首先，如果服务器尚未运行，请启动它：</p><pre><code>$ uwsgi --http-socket 127.0.0.1:5683 --mount /=server:app</code></pre><p>这将在端口5683上启动Flask应用。接下来，你将在Wireshark中开始数据包捕获。此数据包捕获将帮助你查看进出服务器的所有流量。首先在Wireshark上选择Loopback:lo接口：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/01/image-33.png" class="kg-image" alt="image-33" width="1080" height="634" loading="lazy"></figure><p>你可以看到Loopback:lo部分突出显示，这指示Wireshark监视此端口的流量。你可以做得更好，并指定要捕获的端口和协议，可以在捕获筛选器中键入<code>port 5683</code>，在显示筛选器中键入<code>http</code>：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/01/image-34.png" class="kg-image" alt="image-34" width="1080" height="645" loading="lazy"></figure><p>绿色框表示Wireshark对你键入的筛选器感到满意。现在你可以单击左上角的按钮开始捕获：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/01/image-35.png" class="kg-image" alt="image-35" width="1080" height="634" loading="lazy"></figure><p>单击此按钮将在Wireshark中生成一个新窗口：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/01/image-36.png" class="kg-image" alt="image-36" width="1080" height="611" loading="lazy"></figure><p>这个新窗口相当简单，但底部的消息显示<code>&lt;live capture in progress&gt;</code>，这表明它正在工作。别担心什么都没显示出来，这很正常。为了让Wireshark报告任何事情，服务器上必须有一些活动。要获取一些数据，请尝试运行客户端：</p><pre><code>$ SECRET_URL="http://127.0.0.1:5683" python client.py
The secret message is: fluffy tail</code></pre><p>在执行上面的<code>client.py</code>代码之后，你现在应该可以在Wireshark中看到一些条目。如果一切顺利，那么你将看到两个类似于以下内容的条目：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/01/image-37.png" class="kg-image" alt="image-37" width="1080" height="611" loading="lazy"></figure><p>这两个记录表示发生通信的两个部分。第一个是客户机对服务器的请求。当你单击第一个条目时，你将看到大量信息：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/01/image-38.png" class="kg-image" alt="image-38" width="1080" height="612" loading="lazy"></figure><p>很多信息！在顶部，仍然有HTTP请求和响应。选择其中一个条目后，你将看到中间和底部的行填充了信息。</p><p>中间一行提供了协议的详细信息，Wireshark能够为所选的请求标识这些信息。这个详细信息允许你探索HTTP请求中实际发生的事情。Wireshark在中间一行从上到下描述了一些信息，下面是这些信息的快速摘要：</p><ul><li>物理层：描述用于发送请求的物理接口。</li><li>以太网信息：向用户显示的第2层协议，其中包括源和目标MAC地址。</li><li>IPv4：显示源和目标IP地址（127.0.0.1）。</li><li>TCP：包括所需的TCP握手，以便创建可靠的数据管道。</li><li>HTTP：显示关于HTTP请求本身的信息。</li></ul><p>当你展开超文本传输协议层时，可以看到构成HTTP请求的所有信息：</p><p>此图显示脚本的HTTP请求：</p><ul><li>Method: GET</li><li>Path: /</li><li>Version: 1.1</li><li>Headers: Host: 127.0.0.1:5683, Connection: keep-alive, and others</li><li>Body: No body</li></ul><p>你看到的最后一行是十六进制的数据转储。在这个十六进制转储中，你可能会注意到：你实际上可以看到HTTP请求的各个部分。那是因为你的HTTP请求是公开发送的。但是回复呢？如果单击HTTP响应，则会看到一个类似的视图：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/01/image-39.png" class="kg-image" alt="image-39" width="1080" height="726" loading="lazy"></figure><p>同样，也有那三个部分。如果你仔细看这个十六进制转储文件，会看到明文的秘密消息！这对秘密松鼠来说是个大问题。这意味着，如果有兴趣的话，任何有专门技术知识的人都可以很容易地看到这个数据流。那么，你怎么解决这个问题呢？答案是密码学。</p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
