系列文章


mitmproxy 是可编程的,而且非常容易使用。先来看一个简单的例子:

替换内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import re
from mitmproxy import ctx
def request(flow):
remote_host = flow.request.pretty_host
method = flow.request.method
ctx.log.info('remote_host %s'%remote_host)
ctx.log.info('request.host %s' % flow.request.host)
ctx.log.info('request.path %s' % flow.request.path)
ctx.log.info('request.pretty_url %s' % flow.request.pretty_url)
ctx.log.info('request.query %s' % flow.request.query)
ctx.log.info('request.method %s' % flow.request.method)
ctx.log.info('client host %s' % flow.client_conn.address.host)
flow.request.replace('Mozilla', 'Google', re.M)

这个例子打印出了客户端发来的请求中的一些有用的属性,其中:

  • flow.request.pretty_host 请求的域名。如果希望对不同的网站采取不同的策略,可使用该值。
  • flow.request.host 请求的 IP 地址。
  • flow.request.path 请求的路径。如果希望对不同的请求路径采用不同的策略,可使用该值。
  • flow.client_conn.address.host 客户端 IP。如果希望对不同的客户端采取不同的策略,可使用该值。

ctx.log.info 可以将内容打印在 mitmproxy 的 Event log 窗口中(采用快捷键 e 打开) ,下面是访问网站 https://zengrong.net 的 log 内容:

1
2
3
4
5
6
7
remote_host zengrong.net
request.host 121.40.23.108
request.path /
request.pretty_url https://zengrong.net/
request.query MultiDictView[]
request.method GET
client host 192.168.43.196

上面代码中最后还有一句 replace ,是将请求中的所有 Mozilla 字符串替换成 Google 。这里的“所有”包含下面的内容:

  • header
  • path
  • body

在我的这个请求中,仅有一个 Header User-Agent 包含 Mozilla 字符串:

replace

动态修改代理

有 5 个客户端,我希望这 5 个客户端在访问同一个网站的时候,使用不同的代理服务器。该如何处理?

传统的方法是在这 5 个客户端上设置不同的代理服务器。这样存在两个问题:

  1. 有的应用程序可能不走系统代理。
  2. 如果有 100 个客户端呢?

用 mitmproxy 可以解决这些问题。

对于不走系统代理的应用程序,我们可以采用 mitmproxy 应用(一)基础代理 中提到的透明代理的方法来解决。

我们可以将多个客户端的代理服务器全部指向 mitmproxy ,然后在 mitmproxy 中通过编程的方法,为不同的客户端指定不同的代理服务器。

下面是(伪)代码:

1
2
3
4
5
6
7
8
def request(flow):
client_ip = flow.client_conn.address.host
if client_ip == '192.168.0.10':
proxy = ('1.2.3.4', 8080)
else:
proxy = ('3.4.5.6', 8080)
if flow.live:
flow.live.change_upstream_proxy_server(proxy)

需要注意的是,request 在每次请求的时候都会被调用。你可能并不希望每次请求都切换代理服务器,这种情况下,可以通过判断 flow.request.path 或者相关属性来实现条件切换。

全文完

留言