Mitmproxy工作原理

本页内容


Mitmproxy 是一个非常灵活的工具。了解代理过程的工作原理将帮助你更好的使用它。从最简单的未加密代理开始,一直到最复杂的在存在服务器名称指示的情况下对 TLS 保护的流量进行透明代理。

HTTP

将客户端配置为使用 mitmproxy 作为代理是拦截流量的最简单、最可靠的方法。代理协议在HTTP RFC中进行了编码,因此客户端和服务器的行为都得到了很好的定义,并且通常是可靠的。在与 mitmproxy 最简单的交互中,客户端直接连接到代理,并发出如下所示的请求:

GET https://xiaobai.wang/index.html HTTP/1.1

How-mitmproxy-works-explicit.png

  • 客户端连接到代理并发出请求。
  • Mitmproxy 连接到上游服务器并简单地转发请求。

HTTPS

HTTPS 连接的过程完全不同。客户端连接到代理并发出如下所示的请求:

CONNECT xiaobai.wang:443 HTTP/1.1

传统代理既不能查看也不能操作 TLS 加密的数据流,因此 CONNECT 请求只是要求代理打开客户端和服务器之间的管道。这里的代理只是一个促进者——它盲目地向两个方向转发数据,而对内容一无所知。TLS 连接的协商通过此管道进行,随后的请求和响应流对代理完全不透明。

未安装证书去抓包的时候就只会抓到一个CONNECT请求。

mitmproxy 中的 MITM

MITM 是 Man-In-The-Middle 的缩写,这是https抓包的基本原理。 指的是我们用来拦截和干扰这些理论上不透明的数据流的过程。其基本思想是向客户端伪装成服务器,向服务器伪装成客户端,而我们坐在中间解码来自双方的流量。棘手的部分是 证书颁发机构系统旨在通过允许受信任的第三方对服务器的证书进行加密签名以验证它们的合法性,从而完全防止这种攻击。如果此签名不匹配或来自不受信任的一方,则客户端将简单地断开连接并拒绝继续。尽管今天存在的 CA 系统存在许多缺点,但这对于尝试 MITM TLS 连接进行分析通常是致命的。对这个难题的回答是找一个一个值得信赖的证书颁发机构。Mitmproxy 包含一个完整的 CA 实现,可以动态生成拦截证书。为了让客户端信任这些证书,我们手动将 mitmproxy 注册为设备的受信任CA。

远程主机名是什么

要继续这个计划,我们需要知道在拦截证书中使用的域名——客户端将验证证书是否适用于它正在连接的域,如果不是这种情况则中止。乍一看,上面的 CONNECT 请求似乎为我们提供了我们所需要的一切——在这个例子中,这两个值都是“xiaobai.wang”。但是,如果客户端按如下方式启动连接会怎样:

CONNECT 10.1.1.1:443 HTTP/1.1

使用 IP 地址是完全合法的,因为它为我们提供了足够的信息来启动管道,即使它没有透露远程主机名。

Mitmproxy 有一个特殊的机制,可以平滑过度上游的证书嗅探。一旦发现 CONNECT 请求,就会暂停会话的客户端部分,并同时启动与服务器的连接。完成与服务器的 TLS 握手,并检查它使用的证书。然后使用上游证书中的 Common Name 为客户端生成虚拟证书。现在就有了正确的主机名呈现给客户端,即使它从未指定。

主题备用名称subjectAltName

有时证书 Common Name 实际上不是客户端连接的主机名。这是因为证书中的可选主题备用名称字段允许指定任意数量的备用域。如果预期域与其中任何一个匹配,则客户端将继续,即使该域与证书 CN 不匹配。这里的答案很简单:当mitmproxy从上游证书中提取 CN 时,mitmproxy也提取了 SAN,并将它们添加到生成的虚拟证书中。

服务器名称指示 Server Name Indication

TLS 的一大限制是每个证书都需要自己的 IP 地址。这意味着您无法在具有独立证书的多个域共享相同 IP 地址的情况下虚拟主机。在 IPv4 地址池迅速缩小的世界中,这是一个问题,我们有一个解决方案,即 TLS 协议的服务器名称指示 扩展。这让客户端在 TLS 握手开始时指定远程服务器名称,然后让服务器选择正确的证书来完成该过程。

SNI 破坏了我们的上游证书嗅探过程,因为当我们在不使用 SNI 的情况下进行连接时,我们会得到一个默认证书,该证书可能与客户端期望的证书无关。该解决方案是客户端连接过程的另一个棘手的复杂问题。客户端连接后,我们允许 TLS 握手继续,直到SNI 值传递给我们之后。现在我们可以暂停对话,并使用正确的 SNI 值启动上游连接,然后为我们提供正确的上游证书,我们可以从中提取预期的 CN 和 SAN。

让我们将所有这些组合到完整的代理 HTTPS 流中。 How-mitmproxy-works-explicit-https.png

  • 客户端与 mitmproxy 建立连接,并发出 HTTP CONNECT 请求。
  • Mitmproxy 以 响应200 Connection Established,就好像它已经设置了 CONNECT 管道。
  • 客户端认为它正在与远程服务器通信,并启动 TLS 连接。它使用 SNI 来指示它正在连接的主机名。
  • Mitmproxy 连接到服务器,并使用客户端指示的 SNI 主机名建立 TLS 连接。
  • 服务器使用匹配的证书进行响应,其中包含生成拦截证书所需的 CN 和 SAN 值。
  • Mitmproxy 生成拦截证书,并继续在步骤 3 中暂停的客户端 TLS 握手。
  • 客户端通过已建立的 TLS 连接发送请求。
  • Mitmproxy 通过在步骤 4 中启动的 TLS 连接将请求传递给服务器。
此页面最后编辑于2022年8月7日 (星期日) 21:41。