跳至内容

关于 HTTPS

很容易认为 HTTPS 只是“启用”或“禁用”。

但它比这复杂得多。

提示

如果您很着急或不在乎,请继续阅读下一节,了解使用不同技术的逐步设置说明。

要 **从用户的角度了解 HTTPS 的基础知识**,请查看 https://howhttps.works/.

现在,从 **开发者的角度**,在考虑 HTTPS 时,需要注意以下几点。

  • 对于 HTTPS,**服务器** 需要 **拥有由第三方生成的“证书”**。
    • 这些证书实际上是从第三方 **获取** 的,而不是“生成”的。
  • 证书有 **有效期**。
    • 它们会 **过期**。
    • 然后需要 **续订**,**再次从第三方获取**。
  • 连接的加密发生在 **TCP 层级**。
    • 这比 **HTTP** 低一个层次。
    • 因此,**证书和加密** 处理在 **HTTP 之前** 完成。
  • **TCP 不知道“域名”**。只知道 IP 地址。
    • 关于 **特定域名** 的信息位于 **HTTP 数据** 中。
  • **HTTPS 证书** “认证” **某个域名**,但协议和加密发生在 TCP 层级,**在知道** 正在处理哪个域名 **之前**。
  • **默认情况下**,这意味着您只能在每个 IP 地址上拥有 **一个 HTTPS 证书**。
    • 无论您的服务器有多大,或者您在上面运行的每个应用程序有多小。
    • 不过,有一个 **解决方案**。
  • TLS 协议(在 HTTP 之前处理 TCP 层级的加密的协议)有一个 **扩展** 称为 **SNI**。
    • 此 SNI 扩展允许一台服务器(只有一个 **IP 地址**)拥有 **多个 HTTPS 证书** 并提供 **多个 HTTPS 域名/应用程序** 的服务。
    • 要使此功能正常工作,在服务器上运行的 **单个** 组件(程序)必须在 **公共 IP 地址** 上监听,并且必须具有服务器上的 **所有 HTTPS 证书**。
  • **在** 建立安全连接 **后**,通信协议仍然是 **HTTP**。
    • 内容是 **加密** 的,即使它们是使用 **HTTP 协议** 发送的。

通常的做法是让 **一个程序/HTTP 服务器** 在服务器(机器、主机等)上运行并 **管理所有 HTTPS 部分**:接收 **加密的 HTTPS 请求**,将 **解密的 HTTP 请求** 发送到在同一服务器上运行的实际 HTTP 应用程序(在本例中为 **FastAPI** 应用程序),从应用程序获取 **HTTP 响应**,使用相应的 **HTTPS 证书** **对其进行加密**,并使用 **HTTPS** 将其发送回客户端。此服务器通常称为 **TLS 终止代理**。

您可以用作 TLS 终止代理的一些选项是

  • Traefik(它还可以处理证书续订)
  • Caddy(它还可以处理证书续订)
  • Nginx
  • HAProxy

Let's Encrypt

在 Let's Encrypt 出现之前,这些 **HTTPS 证书** 是由值得信赖的第三方出售的。

获取这些证书的过程曾经很繁琐,需要相当多的文书工作,而且证书价格不菲。

但是,**Let's Encrypt** 出现了。

它是 Linux 基金会的一个项目。它以自动化的方式 **免费提供 HTTPS 证书**。这些证书使用所有标准的加密安全性,并且有效期很短(大约 3 个月),因此由于它们缩短了有效期,**安全性实际上更好**。

域名经过安全验证,证书自动生成。 这也允许自动续订这些证书。

想法是自动化获取和续订这些证书,以便您能够 **永远免费获得安全的 HTTPS**。

开发者 HTTPS

这是一个关于 HTTPS API 如何一步一步实现的示例,主要关注对开发人员来说重要的理念。

域名

可能这一切都始于您 **获取** 某个 **域名**。 然后,您将在 DNS 服务器(可能是您同一个云提供商)中配置它。

您可能需要获得一个云服务器(虚拟机)或类似的东西,它将具有一个 固定 **公网 IP 地址**。

在 DNS 服务器中,您将配置一个记录(一个“A 记录”)来将 **您的域名** 指向服务器的公网 **IP 地址**。

您可能只需要在第一次设置所有内容时执行一次此操作。

提示

域名部分发生在 HTTPS 之前,但由于所有内容都依赖于域名和 IP 地址,因此在这里值得一提。

DNS

现在让我们专注于所有实际的 HTTPS 部分。

首先,浏览器将检查 **DNS 服务器** 以了解 **域名的 IP**,在本例中为 someapp.example.com

DNS 服务器将告诉浏览器使用某个特定的 **IP 地址**。 这将是您的服务器使用的公网 IP 地址,您在 DNS 服务器中配置了该地址。

TLS 握手开始

然后,浏览器将与 **端口 443**(HTTPS 端口)上的该 IP 地址通信。

通信的第一部分只是建立客户端和服务器之间的连接,并决定他们将使用的加密密钥等。

客户端和服务器之间这种建立 TLS 连接的交互称为 **TLS 握手**。

带 SNI 扩展的 TLS

服务器中 **只有一个进程** 可以监听特定 **IP 地址** 上的特定 **端口**。 可能会有其他进程监听同一 IP 地址上的其他端口,但每个 IP 地址和端口组合只有一个。

TLS(HTTPS)默认使用特定端口 443。 因此,我们需要的是该端口。

由于只有一个进程可以监听此端口,因此执行此操作的进程将是 **TLS 终止代理**。

TLS 终止代理将能够访问一个或多个 **TLS 证书**(HTTPS 证书)。

使用上面讨论的 **SNI 扩展**,TLS 终止代理将检查它应该使用哪些可用的 TLS(HTTPS)证书来进行此连接,使用与客户端期望的域名匹配的证书。

在本例中,它将使用 someapp.example.com 的证书。

客户端已经 **信任** 生成该 TLS 证书的实体(在本例中为 Let's Encrypt,但我们稍后会看到),因此它可以 **验证** 证书是否有效。

然后,使用证书,客户端和 TLS 终止代理 **决定如何加密** 剩余的 **TCP 通信**。 这就完成了 **TLS 握手** 部分。

在此之后,客户端和服务器将拥有一个 **加密的 TCP 连接**,这就是 TLS 提供的功能。 然后他们可以使用该连接来启动实际的 **HTTP 通信**。

这就是 **HTTPS** 的意义,它只是在 **安全的 TLS 连接** 内的普通 **HTTP**,而不是纯(未加密的)TCP 连接。

提示

请注意,通信的加密发生在 **TCP 级别**,而不是 HTTP 级别。

HTTPS 请求

现在客户端和服务器(特别是浏览器和 TLS 终止代理)拥有一个 **加密的 TCP 连接**,它们可以开始 **HTTP 通信**。

因此,客户端发送一个 **HTTPS 请求**。 这仅仅是通过加密的 TLS 连接的 HTTP 请求。

解密请求

TLS 终止代理将使用之前商定的加密 **解密请求**,并将 **普通(已解密)HTTP 请求** 传输到运行应用程序的进程(例如,运行 FastAPI 应用程序的 Uvicorn 进程)。

HTTP 响应

应用程序将处理请求并向 TLS 终止代理发送 **普通(未加密)HTTP 响应**。

HTTPS 响应

然后,TLS 终止代理将使用之前商定的加密(以 someapp.example.com 的证书开头) **加密响应**,并将响应发送回浏览器。

接下来,浏览器将验证响应是否有效,以及是否使用正确的加密密钥等进行加密。 然后它将 **解密响应** 并进行处理。

客户端(浏览器)将知道响应来自正确的服务器,因为它正在使用他们之前使用 **HTTPS 证书** 商定的加密。

多个应用程序

在同一个服务器(或服务器)上,可能存在 **多个应用程序**,例如其他 API 程序或数据库。

只有一个进程可以处理特定的 IP 和端口(在我们示例中为 TLS 终止代理),但其他应用程序/进程也可以在服务器上运行,只要它们不尝试使用相同的 **公网 IP 和端口组合**。

这样,TLS 终止代理可以处理 **多个域** 的 HTTPS 和证书,用于多个应用程序,然后将请求传输到每个情况下的正确应用程序。

证书续订

在将来的某个时间点,每个证书都会 **过期**(在获取后大约 3 个月)。

然后,将有另一个程序(在某些情况下是另一个程序,在某些情况下可能是同一个 TLS 终止代理)与 Let's Encrypt 通信并续订证书。

**TLS 证书** 与 **域名** 相关联,而不是 IP 地址。

因此,要续订证书,续订程序需要向颁发机构(Let's Encrypt) **证明** 它确实 **“拥有”并控制该域名**。

为了做到这一点,并适应不同的应用程序需求,有几种方法可以做到。 一些流行的方法是

  • 修改一些 DNS 记录.
    • 为此,续订程序需要支持 DNS 提供商的 API,因此,这可能是一个选项,也可能不是一个选项,具体取决于您使用的 DNS 提供商。
  • 在与域名关联的公网 IP 地址上 **运行为服务器**(至少在证书获取过程中)。
    • 如上所述,只有一个进程可以监听特定的 IP 和端口。
    • 这是同一个 TLS 终止代理也负责证书续订过程的一个主要原因。
    • 否则,您可能需要暂时停止 TLS 终止代理,启动续订程序来获取证书,然后在 TLS 终止代理中配置它们,然后重新启动 TLS 终止代理。 这样做并不理想,因为您的应用程序在 TLS 终止代理关闭期间将不可用。

所有这些续订过程(在继续提供应用程序服务的同时)是您可能希望使用 TLS 终止代理 **单独的系统来处理 HTTPS**(而不是直接使用应用程序服务器(例如 Uvicorn)的 TLS 证书)的主要原因之一。

回顾

拥有 **HTTPS** 非常重要,在大多数情况下是 **至关重要的**。 作为开发人员,您在 HTTPS 周围需要投入的大部分精力仅仅是 **了解这些概念** 以及它们的工作原理。

但是,一旦您了解了 **开发者 HTTPS** 的基本信息,就可以轻松地组合和配置不同的工具,以帮助您以简单的方式管理所有内容。

在接下来的几章中,我将向您展示如何为 **FastAPI** 应用程序设置 **HTTPS** 的几个具体示例。 🔒