的工作原理
一、mitmproxy的工作原理
Mitmproxy是一种非常灵活的工具。准确了解代理过程的工作原理将有助于您创造性地部署代理,并考虑其基本假设以及如何解决这些假设。本文档详细介绍了mitmproxy的代理机制,从最简单的未加密显式代理开始,到最复杂的交互操作-在存在服务器名称指示的情况下,对受TLS保护的流量进行透明的代理。
二、显式HTTP
配置客户端以使用mitmproxy作为显式代理是拦截流量的最简单,最可靠的方法。代理协议已在HTTP RFC中进行了编码,因此客户端和服务器的行为都得到了很好的定义,并且通常是可靠的。在与mitmproxy进行的最简单的交互中,客户端直接连接到代理,并发出如下所示的请求:
GET http://example.com/index.html HTTP/1.1
这是一个代理GET
请求-原始HTTP GET
请求的扩展形式,包括模式和主机规范,并且它包含所有需要继续进行的信息mitmproxy
。
- 客户端连接到代理并发出请求。
- Mitmproxy连接到上游服务器,然后继续转发请求。
三、显式HTTPS
显式代理HTTPS
连接的过程是完全不同的。客户端连接到代理并发出如下请求:
CONNECT example.com:443 HTTP/1.1
传统的代理既不能查看也不能操纵TLS加密的数据流,因此CONNECT请求只是要求代理打开客户端和服务器之间的管道。这里的代理只是一个促进者-它在两个方向上都盲目转发数据,而对内容一无所知。TLS连接的协商是通过此管道进行的,随后的请求和响应流对于代理是完全不透明的。
1、mitmproxy中的MITM
这就是mitmproxy
的基本技巧发挥作用的地方。MITM
的名称代表中间人-对我们用来拦截和干扰这些理论上不透明的数据流的过程的引用。基本思想是假装成为客户端的服务器,并假装成为服务器的客户端,而我们坐在中间,解码双方的流量。棘手的部分是 证书颁发机构该系统旨在通过允许受信任的第三方对服务器的证书进行加密签名以验证它们的合法性,来确切地防止这种攻击。如果此签名不匹配或来自非受信方,则安全客户端将简单地断开连接并拒绝继续。尽管当今存在CA系统的许多缺点,但这对于尝试MITM TLS
连接进行分析通常是致命的。我们对这个难题的答案是自己成为一个值得信赖的证书颁发机构。Mitmproxy
包含一个完整的CA
实现,该实现可动态生成拦截证书。为了让客户相信这些证书,我们 注册mitmproxy作为与设备手动可信CA。
2、并发症1:什么是远程主机名?
要继续执行此计划,我们需要知道要在拦截证书中使用的域名-客户端将验证该证书是否适用于与其连接的域,如果不是,则中止。乍一看,上面的CONNECT
请求似乎满足了我们的所有需求-在此示例中,这两个值均为example.com
。但是,如果客户端按以下方式启动了连接,该怎么办:
CONNECT 10.1.1.1:443 HTTP/1.1
使用IP地址是完全合法的,因为它可以为我们提供足够的信息来启动管道,即使它不显示远程主机名也是如此。
Mitmproxy
具有狡猾的机制,可以平滑此上游证书的嗅探。看到CONNECT
请求后,我们将暂停对话的客户端部分,并启动与服务器的同时连接。我们完成了与服务器的TLS握手,并检查了它使用的证书。现在,我们在上游证书中使用公用名为客户端生成虚拟证书。瞧,即使没有指定主机名,我们也可以提供给客户端正确的主机名。
3、并发症2:使用者替代名称
输入下一个并发症。有时,证书公用名实际上不是客户端连接到的主机名。这是因为证书中的可选“使用者备用名称”字段允许指定任意数量的备用域。如果期望的域与这些域中的任何一个相匹配,即使该域与证书CN不匹配,客户端也将继续进行。答案很简单:当我们从上游证书中提取CN时,我们还提取了SAN,并将它们添加到生成的虚拟证书中。
4、并发症3:服务器名称指示
原始TLS的最大限制之一是每个证书都需要自己的IP地址。这意味着您无法在具有独立证书的多个域共享同一IP地址的情况下进行虚拟托管。在一个IPv4地址池迅速缩小的世界中,这是一个问题,并且我们 以TLS协议的服务器名称指示扩展的形式提供了一个解决方案。这使客户端可以在TLS握手开始时指定远程服务器名称,然后使服务器选择正确的证书来完成该过程。
SNI中断了上游证书嗅探过程,因为在不使用SNI的情况下进行连接时,将获得默认证书,该默认证书可能与客户端期望的证书无关。该解决方案是客户端连接过程的另一个棘手的复杂问题。客户端连接后,我们允许TLS握手继续直到刚刚之后的SNI值已经传递给我们。现在,我们可以暂停对话,并使用正确的SNI值启动上游连接,然后为我们提供正确的上游证书,从中可以提取预期的CN和SAN。
5、全部放在一起
让我们将所有这些放到完整的显式代理HTTPS流中。
- 1、客户端建立与mitmproxy的连接,并发出HTTP CONNECT请求。
- 2、Mitmproxy响应为200 Connection Established,就好像它已经设置了CONNECT管道一样。
- 3、客户端认为它正在与远程服务器通信,并启动TLS连接。它使用SNI指示要连接的主机名。
- 4、Mitmproxy连接到服务器,并使用客户端指示的SNI主机名建立TLS连接。
- 5、服务器以匹配的证书作为响应,该证书包含生成拦截证书所需的CN和SAN值。
- 6、Mitmproxy生成拦截证书,并继续在步骤3中暂停的客户端TLS握手。
- 7、客户端通过已建立的TLS连接发送请求。
- 8、Mitmproxy通过在步骤4中启动的TLS连接将请求传递到服务器。
四、透明HTTP
使用透明代理时,连接将重定向到网络层的代理中,而无需任何客户端配置。这使得透明代理非常适合那些您无法更改客户端行为的情况-代理不兼容的Android
应用程序是一个常见示例。
为此,我们需要引入两个额外的组件。第一种是重定向机制,可以透明地将发往Internet
上服务器的TCP
连接重新路由到侦听代理服务器。这通常采用与代理服务器位于同一主机上的防火墙的形式-Linux
上的iptables
或OSX上的 pf
。客户端启动连接后,它将发出原始的HTTP
请求,该请求可能类似于以下内容:
GET /index.html HTTP/1.1
请注意,此请求与显式代理变体不同,因为它忽略了方案和主机名。那么,我们如何知道将请求转发到哪个上游主机呢?执行重定向的路由机制为我们跟踪了原始目的地。每种路由机制都有一种公开此数据的不同方法,因此引入了透明代理工作所需的第二个组件:一个主机模块,该主机模块知道如何从路由器检索原始目标地址。在mitmproxy中,这采取一组内置模块的形式,这些 模块 知道如何与每个平台的重定向机制进行通信。一旦获得了这些信息,这个过程就很简单了。
- 客户端与服务器建立连接。
- 路由器将连接重定向到
mitmproxy
,后者通常在同一主机的本地端口上侦听。然后,Mitmproxy
会咨询路由机制以建立原始目的地。 - 现在,我们只需阅读客户的请求...
- …并将其转发到上游。
五、透明的HTTPS
第一步是确定我们是否应将传入连接视为HTTPS
。这样做的机制很简单-我们使用路由机制找出原始目标端口是什么。所有传入的连接都通过不同的层,这些层可以确定要使用的实际协议。通过在每个连接的开头查找ClientHello
消息,自动TLS
检测可用于SSLv3,TLS 1.0,TLS 1.1
和TLS 1.2
。这独立于所使用的TCP端口起作用。
从这里开始,该过程是我们描述的透明代理HTTP
和显式代理HTTPS
方法的合并。我们使用路由机制来建立上游服务器地址,然后像进行显式HTTPS
连接一样建立CN和SAN
,并处理SNI
。
- 客户端与服务器建立连接。
- 路由器将连接重定向到
mitmproxy
,后者通常在同一主机的本地端口上侦听。然后,Mitmproxy
会咨询路由机制以建立原始目的地。 - 客户端认为它正在与远程服务器通信,并启动
TLS
连接。它使用SNI
指示要连接的主机名。 Mitmproxy
连接到服务器,并使用客户端指示的SNI
主机名建立TLS
连接。- 服务器以匹配的证书作为响应,该证书包含生成拦截证书所需的
CN和SAN值
。 Mitmproxy
生成拦截证书,并继续在步骤3中暂停的客户端TLS
握手。- 客户端通过已建立的
TLS
连接发送请求。 Mitmproxy
通过在步骤4中启动的TLS
连接将请求传递到服务器。
六、注释
除非另有说明,否则“ TLS”的使用在广义上是指SSL(过时和不安全)和TLS(1.0及更高版本)。