这一节教大家编写 Mitmproxy 自定义脚本,这才是 Mitmproxy 真正强大的在方。
Mitmproxy官方给了很多例子:
https://docs.mitmproxy.org/stable/addons-examples/
我们演示一个简单的例子 http-add-header.py
, 为每一个 response 中增一个数字,标明是当前是第几个请求。
"""Add an HTTP header to each response."""
class AddHeader:
def __init__(self):
self.num = 0
def response(self, flow):
self.num = self.num + 1
flow.response.headers["count"] = str(self.num)
addons = [
AddHeader()
]
mitmweb
为了直观的看到请求和响应的数据,我们使用 mitmweb
命令运行脚本。
> mitmweb -s .\http-add-header.py
Web server listening at http://127.0.0.1:8081/
Loading script .\http-add-header.py
Proxy server listening at http://*:8080
...
这个命令就比较厉害了,它启动默认浏览器,并打开一个web版的抓包工具。
打开postman 或其他任何接口调用工具,随便访问一个接口。例如
然后,你会发现mitmproxy已经抓取到请求了,并且为每一个请求的response的响应头增加了一个字段。
有没有很强大。那么我们可以用它来干啥。
- 修改request/response 参数。
- 打断点,解析某个请求的结果并修改里面的参数。
- 过滤请求,只记录某个 host 的请求信息。
- 将某些接口的数据拦截-解析-保存到数据库。
当然,我上面这些大部分你用 fiddler/charles 工具也能完成,但Mitmproxy 可玩性更高,也更加强大。
HTTP生命周期
我们工作中测试的大部分接口都是HTTP的。所以,我们要了解一个HTTP的生命周期。
def http_connect(self, flow: mitmproxy.http.HTTPFlow):
(Called when) 收到了来自客户端的 HTTP CONNECT 请求。在 flow 上设置非 2xx 响应将返回该响应并断开连接。CONNECT 不是常用的 HTTP 请求方法,目的是与服务器建立代理连接,仅是 client 与 proxy 的之间的交流,所以 CONNECT 请求不会触发 request、response 等其他常规的 HTTP 事件。
def requestheaders(self, flow: mitmproxy.http.HTTPFlow):
(Called when) 来自客户端的 HTTP 请求的头部被成功读取。此时 flow 中的 request 的 body 是空的。
def request(self, flow: mitmproxy.http.HTTPFlow):
(Called when) 来自客户端的 HTTP 请求被成功完整读取。
def responseheaders(self, flow: mitmproxy.http.HTTPFlow):
(Called when) 来自服务端的 HTTP 响应的头部被成功读取。此时 flow 中的 response 的 body 是空的。
def response(self, flow: mitmproxy.http.HTTPFlow):
(Called when) 来自服务端端的 HTTP 响应被成功完整读取。
def error(self, flow: mitmproxy.http.HTTPFlow):
(Called when) 发生了一个 HTTP 错误。比如无效的服务端响应、连接断开等。注意与“有效的 HTTP 错误返回”不是一回事,后者是一个正确的服务端响应,只是 HTTP code 表示错误而已。