Python好酷|抓包神器 mitmproxy
mitmproxy(Man-in-the-middle attack,中间人攻击代理)是一款提供交互能力的抓包工具,可以用来拦截、修改、保存 HTTP/HTTPS 请求,对于爬虫尤其是基于APP的爬虫来说,是必不可少的一款神器。mitmproxy 基于Python开发,可以通过Python代码对请求和响应进行自定义过滤和修改。
1. 安装
mitmproxy安装
>> pip install mitmproxy >> mitmproxy --version Mitmproxy: 6.0.2 Python: 3.8.6 OpenSSL: OpenSSL 1.1.1i 8 Dec 2020 Platform: macOS-10.16-x86_64-i386-64bit
证书安装
Chrome输入mimt.it,则打开如下页面,根据操作系统选择对应的证书。
如果是Mac电脑,需要将证书添加为信任文件方可生效。
IPhone的话要开启对证书信任的按钮。设置里面搜索信任。否则无法获取https请求。
2. 启动
mitmproxy 提供了三种启动模式:
- mitmproxy -> 提供一个可交互的命令行界面。
- mitmdump -> 提供一个简单的终端输出。
- mitmweb -> 提供一个浏览器界面。
3. 功能介绍
- HTTP 回放
可以将拦截的http请求,进行request内容修改后重新回放。
- 设置过滤。类似postman interceptor的filter功能。
如果是mimtweb方式开启,则可以在GUI上配置过滤信息。
如果是通过mitmdump开启,则可以使用过滤表达式进行过滤。
a | Match asset in response: CSS, Javascript, Flash, images. |
b regex | Body |
bq regex | Request body |
bs regex | Response body |
c int | HTTP response code |
d regex | Domain |
dst regex | Match destination address |
e | Match error |
h regex | Header |
hq regex | Request header |
hs regex | Response header |
http | Match HTTP flows |
m regex | Method |
marked | Match marked flows |
q | Match request with no response |
s | Match response |
src regex | Match source address |
t regex | Content-type header |
tcp | Match TCP flows |
tq regex | Request Content-Type header |
ts regex | Response Content-Type header |
u regex | URL |
websocket | Match WebSocket flows (and HTTP-WebSocket handshake flows) |
! | unary not |
& | and |
| | or |
举例:URL中仅包含 baidu.com;
mitmproxy -p 8080 u baidu\.com
terminal仅展示baidu.com的http请求。(ps:只是过滤展示而已)
4. 进阶-插件开发
4.1插件
Mitmproxy的插件机制由一组API组成,插件通过响应事件与mitmproxy进行交互,从而使它们能够改变mitmproxy的行为。
插件是mitmproxy的强大组成部分。实际上,许多mitmproxy自己的功能是在一组内置插件中定义的,实现了从反缓存和粘性Cookie之类的功能到我们的入门Webapp的所有功能。内置的插件有助于进行指导性阅读, 你很快就会发现,相当复杂的功能通常可以归结为非常小的,完全独立的模块。Mitmproxy为第三方脚本编写者和扩展程序提供了与内置功能完全相同的一组工具。
创建一个python脚本 anatomy.py。
from mitmproxy import ctx class Counter: def __init__(self): self.num = 0 def request(self, flow): self.num = self.num + 1 ctx.log.info("We've seen %d flows" % self.num) addons = [ Counter() ]
上面是一个简单的插件,用于跟踪我们拦截HTTP请求的数量。每次看到新的HTTP请求时,它都会使用mitmproxy的内部日志记录机制来打印出来。可以在交互式工具的事件日志中或mitmdump的控制台中看到输出结果。
在示例中使用mitmpdump指令:
> mitmdump -s ./anatomy.py
4.2配置
mitmproxy的核心是全局选项存储,其中包含确定mitmproxy及其附加组件行为的设置。可以从配置文件中读取选项,在命令行上进行设置,并由用户即时进行交互更改。
下面是在更改响应headers信息,增加计数的例子:
from mitmproxy import ctx class AddHeader: def __init__(self): self.num = 0 def load(self, loader): loader.add_option( name = "addheader", typespec = bool, default = False, help = "Add a count header to responses", ) def response(self, flow): if ctx.options.addheader: self.num = self.num + 1 flow.response.headers["count"] = str(self.num) addons = [ AddHeader() ]
>> env http_proxy=http://localhost:8080 curl -I http://baidu.com HTTP/1.1 200 OK Date: Sat, 15 May 2021 02:41:52 GMT Server: Apache Last-Modified: Tue, 12 Jan 2010 13:48:00 GMT ETag: "51-47cf7e6ee8400" Accept-Ranges: bytes Content-Length: 81 Cache-Control: max-age=86400 Expires: Sun, 16 May 2021 02:41:52 GMT Connection: Keep-Alive Content-Type: text/html count: 5
4.3指令
命令允许用户与插件进行积极的交互-查询其状态。像options一样,将键入命令,并在运行时检查命令的调用和返回的数据。命令是一个非常强大的结构-例如mitmproxy控制台中的所有用户交互都是通过将命令绑定到键来构建的。如下插件,开发一个指令 myaddon.addheader,在terminal输入即可向请求头增加一个key: myheader
import typing from mitmproxy import command from mitmproxy import ctx from mitmproxy import flow class MyAddon: @command.command("myaddon.addheader") def addheader(self, flows: typing.Sequence[flow.Flow]) -> None: for f in flows: f.request.headers["myheader"] = "value" ctx.log.alert("done") addons = [ MyAddon() ]
>> mitmproxy -s ./examples/addons/commands-flows.py >> :myaddon.addheader @focus
4.4脚本
addons机制具有一种非常便捷的方式,可以将模块作为一个整体视为一个addon对象。这使我们可以将事件处理程序函数放在模块作用域中。例如,下面是一个完整的脚本,它向每个请求头添加键值对。
def request(flow): flow.request.headers["myheader"] = "value"
拦截特定URL的请求并发送任意响应的示例:
from mitmproxy import http def request(flow: http.HTTPFlow) -> None: if flow.request.pretty_url == "http://example.com/path": flow.response = http.HTTPResponse.make( 200, # (optional) status code b"Hello World", # (optional) content {"Content-Type": "text/html"} # (optional) headers )
可以基于mitmproxy支持的所有事件开发自己的脚本;附 /api/events.html
5. 项目实践
动态获取知乎视频专栏信息,不停刷知乎就会不停打印输出。
#!/usr/bin/env python3 # _*_ coding: utf-8 _*_ import json import re from mitmproxy import ctx class zhihu: def response(self, flow): # 提取请求的 url 地址 request_url = flow.request.url # 通过 zhihu 字符串,过滤出 知乎APP 的请求和返回数据 if bool(re.search(r"zhihu", request_url)): print("request_url >>> ", request_url) response_body = flow.response.text response_url = flow.request.url print("response_url >>> ", response_url) ctx.log.info("打印输出:" + response_body) data = json.loads(response_body) try: ware_infos = data.get("data") av_info = {} # 以下逻辑需要提前熟悉接口响应信息结构,再做出解析 if ware_infos is not None: for ware_info in ware_infos: av_info["标题"] = ware_info['card']['title']['plain_text'] av_info["视频地址"] = ware_info['card']['action']['intent_url'] av_info["UP主"] = ware_info['card']['author']['name'] print(av_info) except: ctx.log.info("跳过") addons = [ zhihu() ]
执行
mitmdump -s jingdong.py u zhihu.com