mitmproxy:灵活的网络调试工具

文摘   科技   2024-01-23 10:48   浙江  

什么是 mitmproxy


mitmproxy,顾名思义,就是用于MITM的proxy。MITM即中间人攻击(man-in-the-middle-attack)。用于中间人攻击的代理首先会向正常的代理一样转发请求,保障服务端与客户端的通信,其次,会适时的查、记录其截获的数据,或篡改数据,引发服务端或客户端特定的行为。



不同于 fiddler 或 wireshark 等抓包工具,mitmproxy 不仅可以截获请求帮助开发者查看、分析,更可以通过自定义脚本进行二次开发。举例来说,利用 fiddler 可以过滤出浏览器对某个特定 url 的请求,并查看、分析其数据,但实现不了高度定制化的需求,类似于:“截获对浏览器对该 url 的请求,将返回内容置空,并将真实的返回内容存到某个数据库,出现异常时发出邮件通知”。而对于 mitmproxy,这样的需求可以通过载入自定义 python 脚本轻松实现。


mitmproxy 作为正向代理模式,可以用作仿真爬虫,在web测试中,也可以按需求修改response或者request,以方便测试人员测试一些比较难触发的异常场景。


如何安装


在linux 或者mac 中,可以直接运行: 

sudo pip3 install mitmproxy


在windows中,以管理员身份运行cmd 或者power shell:  

pip3 install mitmproxy


如何使用


要启动mitmproxy,可以用以下任一3个命令: mitmproxy, mitmdump, mitmweb. 这三个命令功能一致,且都可以加载自定义脚本,唯一的区别是交互界面的不同。


我就介绍一下我经常用到的:  mitmwebmitmdump


mitmweb


mitmweb 命令启动后,会提供一个 web 界面,用户可以实时看到发生的请求,并通过 GUI 交互来过滤请求,查看请求数据。


mitmweb 使用场景


在编写rest api自动化脚本时,经常需要查看http 请求,这时候就可以首先启动一个web 服务, 命令如下: mitmweb --ssl-insecure -p 8999 (使用--ssl-insecure 是为了忽略不被信任的自签名证书):



这时候会同时打开一个web 页面:



然后脚本里进行如下配置:


# update env.yaml to include proxytest_bot:  host: https://tec-l-1183620.labs.microstrategy.com/MicroStrategyLibrary  user:    name: mstr1    password: newman1#    locale: en_us    id: 54F3D26011D2896560009A8E67019608 proxies:   http: http://127.0.0.1:8999   https: http://127.0.0.1:8999  projectId:    - B7CA92F04B9FAE8D941C3E9B7E0CD754  dossier:    - 6A0470264C4D68CD5308FFB1CB198FA5

# http request is defined as below:requests_response = requests.request(            method=self.method,            url=self.host + self.path,            headers=self.headers,            params=self.query,            data=raw,            proxies=self.proxies,            verify=False        )        r = Response(requests_response)


配置完成后,就能在web 页面看到所有相关的http请求了。debug 脚本的时候就可以不需要打断点去查看相关请求, 着实高效了不少。



mitmdump


mitmdump命令启动后没有界面,程序默默运行,所以 mitmdump 无法提供过滤请求、查看数据的功能,只能结合自定义脚本,默默工作。


mitmdump 配合自定义脚本,就可以发挥它强大的脚本二次开发能力了。


使用-s 可以指定一个脚本来处理接获的数据: mitmdump -s script.py


mitmdump 使用场景1:rewrite and map


  1. 测试长字符串。修改ai service 返回的推荐内容。推荐内容是根据当前的数据集进行推荐的,如果要测试长文本的话,就会比较难。一种方式就是hack response来mock 长文本。

  2. 修改custom app 的contentType  这个参数,这个参数是不被暴露出来的,如果想要修改需要调用api,过程比较繁琐。

  3. 测试异常响应时前端表现。比如当aiService 返回400 或者500 error时前端表现。

具体代码如下:

def response(flow: http.HTTPFlow):     # update recommneded question to be long text    if "/api/aiservice/chats/recommendations/dossier" in flow.request.path:        # read long text from txt file        with open('/Users/xuyin/Downloads/1.txt', 'r') as f:            text = f.read()        data = json.loads(flow.response.content)        data['result']['insights'][0] = text
       flow.response.text = json.dumps(data)
   # update content type of MicroStrategy application    if '/api/v2/applications?outputFlag=FILTER_AUTH_MODES' in flow.request.path:        data = json.loads(flow.response.content)        for item in data['applications']:            if item['name'] == 'MicroStrategy':                item['homeScreen']['contentType']['bot'] = False        flow.response.text = json.dumps(data)
   if 'api/aiservice/chats/dossier' in flow.request.path:        # update status code to be 400        flow.response.status_code = 400        data = json.loads(flow.response.content)        data['message'] = 'Sorry AI service reports an error'        flow.response.text = json.dumps(data)

结果如下:


未经mock之前,返回建议中的相关建议字数都不长。


mock之后,第一条已经被更新。


未经mock之前,library的主页面可以看到机器人的选项。


mock之后,机器人的选项在侧边栏已消失。


未经mock之前


mock之后,当模拟400 error的时候,response body里的message已经被更新,status code也从原来的200变成了400。


mitmdump 使用场景2:爬虫


除此之外, 使用mitmproxy 也可以实现网页页面爬虫的提取功能:


比如我想抓取一下页面的所有的问题,回复已经回复时间。当消息很多的时候,一条一条复制粘贴显然太低效了。



这时候只需要编写脚本然后运行以下命令(使用-w logfile 将输出存储到指定文件)


mitmdump  -s /Users/xuyin/PycharmProjects/ceshkaifa/mock/demo.py --ssl-insecure -p 8999 -w ~/Downloads/answers.txt


把所有抓取到的信息存到指定文件中,就可以了。


脚本如下:


def response(flow: http.HTTPFlow):    if '/api/bots/BD985181654E0D61180C5DA4F2DE3629/chats' in flow.request.path:        ctx.log.info("-------start to catch chat messages-------\n")        data = json.loads(flow.response.content)        cnt = 1        ctx.log.info(f"-------{data['chats'][0]['messages']}-------\n")        for item in data['chats'][0]['messages']:            question = item['question']['text']            answers = "\n".join(answer['text'] for answer in item['answers'])            creation_date = item['creationDate']            ctx.log.info(f"-------{cnt}-------\n")            ctx.log.info(f"-------question: {question}-------\n")            ctx.log.info(f"-------answer: {answers}-------\n")            ctx.log.info(f"-------creation_date: {creation_date}-------\n")            cnt += 1


最后获取到内容如下:



其他代理模式


讲了这么多正向代理模式,mitmproxy 还支持其他的代理,比反向代理,上行代理, 透明代理和socks5代理。这里我就简单介绍下如何使用mitmproxy进行反向代理:


众所周知,nginx 也支持反向代理,但是配置略为繁琐,比如openai 的api endpoint 国内网络是无法直接访问的,如果有一个跳板机,那么只需要在跳板机上运行mitmproxy 反向代理模式,那么即使本机不挂代理,也可以轻轻松松访问openai 的api 了。


通过使用 --mode reverse 就可以指定代理模式为反向代理(默认为正向代理模式)


在跳板机运行以下命令: 


mitmdump -p 8090 --mode reverse:https://api.openai.com/



然后在jupternotebook 里修改环境变量,把OPENAI_API_BASE改成代理的地址,就大功告成了。



对比nignx 对于转发的配置,mitmproxy只用一句话就能搞定,还是非常方便的。


http{log_format  main  '$remote_addr -  [$time_local] '                      '$status   ';
access_log  /var/log/nginx/access_http.log  main;    server{        listen 8060;        server_name 10.23.35.208;        location / {        proxy_pass  https://api.openai.com/;        proxy_ssl_server_name on;        proxy_set_header Host api.openai.com;        proxy_set_header Connection '';         proxy_http_version 1.1;        chunked_transfer_encoding off;        proxy_buffering off;        proxy_cache off;        proxy_set_header X-Forwarded-For $remote_addr;        proxy_set_header X-Forwarded-Proto $scheme;        }        }


以上只是mitmproxy的基本使用方式,mitmproxy 的github repo 本身也提供了很多addons 可以直接进行调用,mitmproxy 配合selenium 就可以实现更多的网页爬虫功能,感兴趣的小伙伴可以自行搜索。


微策略 商业智能
微策略 MicroStrategy (Nasdaq: MSTR) 是企业级分析和移动应用软件行业的佼佼者。关注我们了解行业资讯、技术干货和程序员日常。
 最新文章