由于我对所用的拦截工具感到厌烦,我才开始有关mitmproxy的工作。我有一个轻度抱怨的长长地列表- 它们没有足够的灵活性,没有足够的可编程性,大多数都是用java(我不喜欢的一种语言)写的,等等。不过,最严重的问题是不透明性。最好用的工具全部是闭源的和商业性的。SSL拦截是一个复杂和精细的过程,并且从某一点开始,无法精确的理解你的代理正在做什么就没办法继续运行。
下文现在是mitmproxy官方文档的一部分。它对mitmproxy的拦截过程做了详细的描述,并且或多或少是我首次启动这个项目的时候我希望所拥有的概要性文档。我以例子开始着手,开始用的最简单的非加密的显式代理,直到最复杂的交互式包含SNI的SSL加密流量的透明代理。
配置客户端使用mitmproxy作为一个显式代理是拦截流量最简单,最可靠的办法。代理协议被编纂在 HTTP RFC, 所以客户端和服务器的行为都是被很好的定义并且通常是可靠的。一个客户端尽可能简单的与mitmproxy互动,通过直接连接到代理服务器,发出请求,看起来像这样:
GET http://example.com/index.html HTTP/1.1
这是GET代理请求-传统HTTP GET请求的一种扩展形式(包括一个schema和主机规格),它包括了mitmproxy需要转达请求上游的所有信息。
1.客户端连接到代理服务器发出请求。 | |
2 .Mitmproxy连接到上游服务器,简单的转发请求。 | |
显式代理HTTPS的连接过程是完全不同的。客户端通常是这样连接到代理服务器的:
CONNECT example.com:443 HTTP/1.1
传统的代理服务器既不监视也不操纵SSL加密的数据流,那一个连接请求只是简单请求代理服务器在客户端和服务器之间假设一条管道。这里的代理服务器就像是一个催化器-它盲目在两个方向上转发数据却不关心数据的内容。加密的的 SSL数据在这条通道上传输,接下来的的请求和响应对代理服务器则是完全不透明。
CONNECT 10.1.1.1:443 HTTP/1.1使用IP地址是非常合理的,因为它给我们足够的信息初始化传输管道,即使它不给出远端的主机名。mitmproxy使用了一个精巧的机制最终抚平了这个缺陷-上游证书侦听。当我们一看到CONNECT请求,我们立即暂停会话的客户端,然后向服务器发起一个相同的连接。我们完成了同服务器的SSL握手,然后查看它使用的证书。现在我们使用上游SSL证书里的常用名来产生一个对客户端仿制的证书。瞧,即使客户端从没有指明的情况下,我们也可以向客户端显示正确的主机名。
常用的SSL大的限制之一就是每个证书需要有它自己的IP地址。这意味着你不能做具有独立证书的多个域共享同一个IP地址的虚拟主机。在这个快速缩减IPv4地址池的世界里,这是个问题,不过我们提出了对SSL和TLS协议的服务器名字指示扩展的解决方案,这允许客户端在SSL握手开始的时候指明远端服务器名字,然后就让服务器选择正确的证书以完成这个过程。
服务器名字指示(SNI)破坏了上游证书侦听的过程,因为当我们不使用服务器名字指示(SNI)而连接的时候,我们获得的提供服务的默认证书,这也许与客户端期望的证书没有任何关系。解决的方法是对客户端的连接过程继续技巧性的复杂化。客户端连接后,我们允许SSL握手继续,直到服务器名字指示(SNI)传送给我们。现在我们暂停这个会话,然后使用正确的服务器名字指示(SNI)启动上游连接,接着服务器给我们提供一个正确的上游证书,我们从这个证书里可以提取期望的常用名(CN)和服务器备用名(SAN)。
这儿还有另一种方法。由于mitmproxy使用的SSL库的限制,我们检测不到连接发送服务器名字指示(SNI)请求对上游认证侦听来说太迟了这种情况。因此,实践中我们使用了常用的SSL连接来侦听上游非服务器名字指示(SNI)的认证,接着如果客户端发送了一个服务器名字指示(SNI)通知的话,就释放这个连接。如果你使用包侦听器看到你的数据流的话,那么当发送服务器名字指示的(SNI)请求时候你将能看到两个到服务器的连接。其中的一个在SSL握手之后立刻关闭。很幸运,实践中这几乎从来都不是问题。
总结让我们把前面几段总结为完整的显式代理的HTTPS流。
为了获得透明代理,我们必须介绍两个额外的组件。第一个是重定向机制,它透明地重新路由目的地在互联网上的服务器的TCP连接到正在侦听的代理服务器。这通常在与代理服务器相同的主机上采用防火墙的形式实现-Linux的iptables或者OSX的pf。一旦客户端初始化了连接,它将发起常见的HTTP请求,可能看起来如下:
GET /index.html HTTP/1.1
注意,这儿的请求与显式代理的请求是不同的,因为它省略了协议和主机名。那么我们是怎样知道向前转发请求的是哪个上游主机的呢?执行重定向的路由机制追踪着我们的原始目的地。每个路由机制都用不同方式显示这些数据,因此这儿介绍透明代理工作所需要的第二个组件:主机模块。它知道如何从路由里获取原始的目的地址。在mitmproxy里,采用了内置模块集的方式来明确怎样和每个平台重定向机制会话。一旦我们有了这个信息,处理过程将非常明了。
1.客户端发起到服务器的连接。
2.路由器将重定向这个连接到mitmproxy,mitmproxy通常侦听在同一个主机的本地端口上。mitmproxy然后查询路由机制以确定原始目的地址。
3.现在,我们仅仅读客户端的请求......
4....然后向前转发请求到上游主机
2KB项目(www.2kb.com,源码交易平台),提供担保交易、源码交易、虚拟商品、在家创业、在线创业、任务交易、网站设计、软件设计、网络兼职、站长交易、域名交易、链接买卖、网站交易、广告买卖、站长培训、建站美工等服务