什么是mitmproxy
mitmproxy是一个支持HTTP和HTTPS的抓包程序,有类似Fiddler、Charles的功能,只不过它是一个控制台的形式操作。
mitmproxy还有两个关联组件。一个是mitmdump,这是它的核心组件,监听信息流,和使用其他语言(python,js)控制。它是mitmproxy的命令行接口,利用它我们可以对接Python脚本,用Python实现监听后的处理。另一个是mitmweb,它是一个Web程序,通过它我们可以清楚观察mitmproxy捕获的请求(类似于客户端)。python的安装如下:
pip3 install mitmproxy
mitmproxy核心功能
拦截HTTP和HTTPS请求和响应。
模拟客户端发起请求,模拟服务端返回响应。
利用反向代理将流量转发给指定的服务器。
利用Python对HTTP请求和响应进行实时处理。
核心功能在于第四点,我们可以通过Python处理和控制HTTP请求,相对于传统的抓包工具chalers,findder这就是他的核心优点。它提供了我们用程序控制HTTP/HTTPS请求的方式(我其实更喜欢说数据流,但是HTTP类的数据只是其中一部分),爬虫就是看中这个优点,让我们可以更好的脱离人力,去实现自动化操作,这也是我想介绍一下这个工具的核心。
代理抓包原理
和Charles一样,mitmproxy运行于自己的PC上,mitmproxy会在运行环境下监听一个端口,然后开启一个代理服务,这个服务实际上是一个HTTP/HTTPS的代理。
手机和PC在同一个局域网内,设置代理为mitmproxy的代理地址,这样手机在访问互联网的时候流量数据包就会流经mitmproxy,mitmproxy再去转发这些数据包到真实的服务器,服务器返回数据包时再由mitmproxy转发回手机,这样mitmproxy就相当于起了中间人的作用,抓取到所有Request和Response,另外这个过程还可以对接mitmdump,抓取到的Request和Response的具体内容都可以直接用Python来处理,比如得到Response之后我们可以直接进行解析,然后存入数据库,这样就完成了数据的解析和存储过程。
其实很多抓包都是通过这个原理,甚至像我常用的SPLASH(渲染工具,类似于Selenium,只不过更优雅,可以把它看成一个定制化的selenium的微服务)都是通过类似的原理。
mitmproxy使用
手机抓包大家都知道要安装证书就是相当于一个护照有了它你才可以出国旅游,在你安装好mitmdump,我们需要在同一个局域网下,填入我们启动mitmproxy服务的机器的IP,然后输入端口,这样手机的数据将会流过这个端口。
手机配置好以后我们就开始使用了首先是访问mitm.it网站安装证书(不管是chalers还是finddler实现手机抓包都需要证书),且需要手机设置信任证书,这里就不赘述了。
我这里提供几个简单的实例:
- 使用命令启动mitmproxy,并将截获的数据保存到指定文件中
mitmdump -w outfile
- 使用指定命令截获的数据,如指定处理脚本文件为test.py.
mitmdump -s test.py
- 日志输出
from mitmproxy import ctx
def request(flow):
#修改请求头
flow.request.headers['User-Agent'] = 'MitmProxy'
ctx.log.info(str(flow.request.headers))
ctx.log.warn(str(flow.request.headers))
ctx.log.error(str(flow.request.headers))
- Request请求
from mitmproxy import ctx
#所有的请求都会经过request
def request(flow):
info = ctx.log.info
# info(flow.request.url)
# info(str(flow.request.headers))
# info(str(flow.request.cookies))
# info(flow.request.host)
# info(flow.request.method)
# info(str(flow.request.port))
# info(flow.request.scheme)
print(flow.request.method,":",flow.request.url)
- Response响应
from mitmproxy import ctx
#所有的请求都会经过request
def response(flow):
info = ctx.log.info
#info(flow.response.url)
#info(str(flow.response.headers))
#info(str(flow.response.cookies))
info(str(flow.response.status_code))