在接口调试、数据采集、接口自动化测试、网络请求篡改等场景中,抓包工具是开发者和测试工程师的必备利器。市面上的抓包工具层出不穷,比如Fiddler、Charles、Wireshark,而**mitmproxy**(及其命令行工具mitmdump)凭借**开源免费、跨平台、强大的脚本扩展能力**,成为了自动化场景下的首选工具。
其中,**mitmdump**是mitmproxy的命令行版本,它不仅具备mitmproxy的核心抓包能力,还支持通过Python脚本自定义处理请求和响应------这意味着我们可以将抓包、修改、验证、存储等操作全部自动化,摆脱手动操作的繁琐。本文将从**基础入门**、**核心脚本开发**、**实战场景落地**三个维度,全面讲解mitmdump的使用方法,让你轻松玩转网络请求的自动化处理。
一、什么是mitmdump?
mitmdump是**mitmproxy**套件中的命令行工具,mitmproxy是一款基于Python的开源中间人攻击(MITM)工具,能够捕获HTTP/HTTPS、WebSocket等协议的网络请求。
核心优势
-
命令行操作:无需图形界面,适合服务器环境、自动化脚本执行;
-
Python脚本扩展:通过自定义Python脚本,可实现请求/响应的修改、过滤、验证、存储等任意逻辑;
-
跨平台:支持Windows、macOS、Linux,还能捕获手机、模拟器的网络请求;
-
支持多种协议:HTTP/1.1、HTTP/2、HTTPS、WebSocket、TCP等;
-
数据持久化:可将抓包数据保存为文件,也可从文件读取并重放请求。
工作原理
mitmdump的核心是**中间人攻击**:
-
启动mitmdump后,它会在本地开启一个代理服务器(默认端口8080);
-
客户端(浏览器、手机、程序)将代理设置为mitmdump的地址和端口;
-
客户端发送的请求会先经过mitmdump,再由mitmdump转发给目标服务器;
-
目标服务器的响应会先经过mitmdump,再由mitmdump转发给客户端;
-
在这个过程中,mitmdump可以拦截、修改、记录所有的请求和响应。
注:对于HTTPS请求,需要安装mitmdump的CA证书,否则无法解密请求内容。
二、环境准备:安装与证书配置
1. 安装mitmdump
mitmdump基于Python,推荐使用pip安装:
bash
# 安装最新版本
pip install mitmproxy
验证安装成功:
bash
# 查看版本
mitmdump --version
# 查看帮助
mitmdump --help
2. 配置CA证书(关键:抓HTTPS请求)
mitmdump默认无法解密HTTPS请求,需要安装并信任mitmdump的CA证书。
步骤1:生成CA证书
启动一次mitmdump(无需参数),然后关闭,mitmdump会自动在用户目录下生成CA证书:
bash
# 启动mitmdump,然后按Ctrl+C关闭
mitmdump
证书默认存储路径:
-
Windows :
C:\Users\<用户名>\.mitmproxy -
macOS/Linux :
~/.mitmproxy
路径下的核心证书文件:
-
mitmproxy-ca.pem:PEM格式的根证书 -
mitmproxy-ca-cert.pem:用于导入浏览器/系统的证书 -
mitmproxy-ca-cert.cer:Windows系统的证书格式
步骤2:安装系统证书(以macOS为例)
-
打开
~/.mitmproxy目录,双击mitmproxy-ca-cert.pem; -
在弹出的"钥匙串访问"中,选择"登录"钥匙串,点击"添加";
-
找到"mitmproxy"证书,右键选择"显示简介";
-
在"信任"选项卡中,设置"使用此证书时"为"始终信任"。
步骤3:安装手机证书(捕获手机请求)
-
确保手机和电脑在同一局域网;
-
电脑启动mitmdump:
mitmdump -p 8080; -
手机设置代理:IP为电脑的局域网IP,端口为8080;
-
手机浏览器访问
mitm.it,根据系统(iOS/Android)下载并安装证书; -
iOS需在"设置→通用→关于本机→证书信任设置"中开启信任;Android需在设置中找到证书并设为信任。
三、mitmdump基础使用:命令行操作
mitmdump的基础命令主要用于启动代理、保存抓包数据、读取抓包数据,以下是常用命令:
1. 启动基础代理
bash
# 默认端口8080启动
mitmdump
# 指定端口启动(如8888)
mitmdump -p 8888
# 启动时显示详细日志(调试用)
mitmdump -v
2. 保存抓包数据到文件
bash
# 将抓包数据保存为mitmdump格式(.mitm)
mitmdump -w capture.mitm
# 指定端口并保存,同时过滤只保存指定域名的请求(如baidu.com)
mitmdump -p 8080 -w baidu_capture.mitm -q "~d baidu.com"
其中-q参数用于过滤请求,支持的过滤规则如下(常用):
-
~d domain:匹配域名(如~d baidu.com) -
~p port:匹配端口(如~p 8080) -
~m method:匹配请求方法(如~m GET、~m POST) -
~u url:匹配URL(如~u /api/login) -
~s status:匹配响应状态码(如~s 200) -
组合过滤:
~m POST ~d api.example.com(POST请求且域名为api.example.com)
3. 从文件读取抓包数据
bash
# 读取抓包文件并显示
mitmdump -r capture.mitm
# 读取文件并过滤请求(只显示POST请求)
mitmdump -r capture.mitm -q "~m POST"
# 读取文件并重放请求(将抓包的请求重新发送)
mitmdump -r capture.mitm --replay
4. 其他常用参数
bash
# 忽略指定域名的请求(如忽略google.com)
mitmdump --ignore-hosts google.com
# 设置反向代理(将请求转发到目标服务器)
mitmdump -p 8080 --reverse-proxy http://localhost:8000
四、核心能力:Python脚本自定义处理请求/响应
mitmdump的真正强大之处在于**支持Python脚本扩展**。我们可以编写脚本,对拦截到的请求和响应进行任意处理,比如修改参数、篡改响应、自动验证、数据存储等。
1. 脚本的基本结构
mitmdump的Python脚本通过定义特定的函数来处理请求和响应,核心函数有:
-
request(flow):处理请求(请求发送到服务器前触发) -
response(flow):处理响应(服务器响应后发送到客户端前触发) -
start():脚本启动时执行(初始化操作,如连接数据库) -
done():脚本结束时执行(清理操作,如关闭数据库连接)
其中,flow是核心对象,包含了请求和响应的所有信息:
-
flow.request:请求对象(包含URL、方法、头、参数、请求体等) -
flow.response:响应对象(包含状态码、头、响应体等)
2. 实战案例1:修改GET请求参数
需求:拦截所有访问https://api.example.com/user的GET请求,将参数id=1改为id=100。
编写脚本modify_get_param.py:
python
from mitmproxy import http
def request(flow: http.HTTPFlow) -> None:
# 过滤指定URL的GET请求
if flow.request.pretty_url.startswith("https://api.example.com/user") and flow.request.method == "GET":
# 获取请求参数
params = flow.request.query
# 修改参数id的值
if "id" in params:
params["id"] = "100"
print(f"修改GET参数:id从{params.get('id', '原数值')}改为100")
# 重新设置参数(可选,因为params是引用类型,修改后自动生效)
flow.request.query = params
启动mitmdump并加载脚本:
bash
mitmdump -p 8080 -s modify_get_param.py
3. 实战案例2:修改POST请求的JSON请求体
需求:拦截https://api.example.com/login的POST请求,将请求体中的password改为123456。
编写脚本modify_post_body.py:
python
import json
from mitmproxy import http
def request(flow: http.HTTPFlow) -> None:
# 过滤指定URL的POST请求
if flow.request.pretty_url == "https://api.example.com/login" and flow.request.method == "POST":
try:
# 解析JSON请求体
request_body = json.loads(flow.request.content.decode("utf-8"))
# 修改password
if "password" in request_body:
original_pwd = request_body["password"]
request_body["password"] = "123456"
print(f"修改POST请求体:password从{original_pwd}改为123456")
# 重新设置请求体
flow.request.content = json.dumps(request_body).encode("utf-8")
except json.JSONDecodeError:
# 非JSON请求体,跳过
pass
启动脚本:
python
mitmdump -p 8080 -s modify_post_body.py
4. 实战案例3:修改响应内容(篡改JSON数据)
需求:拦截https://api.example.com/user/info的响应,将username改为test_user。
编写脚本modify_response.py:
python
import json
from mitmproxy import http
def response(flow: http.HTTPFlow) -> None:
# 过滤指定URL的响应
if flow.request.pretty_url == "https://api.example.com/user/info":
try:
# 解析JSON响应体
response_body = json.loads(flow.response.content.decode("utf-8"))
# 修改username
if "username" in response_body:
original_name = response_body["username"]
response_body["username"] = "test_user"
print(f"修改响应体:username从{original_name}改为test_user")
# 重新设置响应体
flow.response.content = json.dumps(response_body).encode("utf-8")
# 可选:修改响应状态码
# flow.response.status_code = 404
except json.JSONDecodeError:
pass
5. 实战案例4:过滤并保存特定响应数据(如图片)
需求:拦截所有图片请求(后缀为.jpg/.png),并保存到本地文件夹。
编写脚本save_images.py:
python
import os
from mitmproxy import http
# 初始化:创建保存图片的文件夹
def start() -> None:
if not os.path.exists("captured_images"):
os.makedirs("captured_images")
print("图片保存文件夹已创建:captured_images")
def response(flow: http.HTTPFlow) -> None:
# 过滤图片请求(通过后缀或Content-Type)
url = flow.request.pretty_url
if url.endswith((".jpg", ".png", ".jpeg")) or "image/" in flow.response.headers.get("Content-Type", ""):
# 获取图片名称(从URL中提取)
image_name = url.split("/")[-1]
# 处理特殊字符(避免文件名错误)
image_name = image_name.replace("?", "_").replace("&", "_")
# 保存图片
with open(f"captured_images/{image_name}", "wb") as f:
f.write(flow.response.content)
print(f"保存图片:{image_name}")
6. 实战案例5:接口自动化测试(自动断言响应)
需求:拦截https://api.example.com/order/list的响应,自动验证状态码为200,且响应体中包含data字段。
编写脚本api_test.py:
python
import json
from mitmproxy import http
from mitmproxy.log import log
def response(flow: http.HTTPFlow) -> None:
# 过滤指定接口
if flow.request.pretty_url == "https://api.example.com/order/list":
# 断言1:响应状态码为200
assert flow.response.status_code == 200, f"状态码断言失败:预期200,实际{flow.response.status_code}"
# 断言2:响应体包含data字段
try:
response_body = json.loads(flow.response.content.decode("utf-8"))
assert "data" in response_body, "响应体缺少data字段"
print("接口断言通过!")
except json.JSONDecodeError:
log.error("响应体不是JSON格式,断言失败")
except AssertionError as e:
log.error(f"接口断言失败:{e}")
注:断言失败时,mitmdump会抛出异常并记录日志,可结合CI/CD工具实现自动化测试告警。
五、进阶技巧:提升mitmdump使用效率
1. 结合JSONPath提取响应数据
对于复杂的JSON响应,可使用jsonpath-ng库提取特定字段,需先安装:
python
pip install jsonpath-ng
示例:提取响应中所有订单的ID:
python
import json
from jsonpath_ng import parse
from mitmproxy import http
def response(flow: http.HTTPFlow) -> None:
if "order/list" in flow.request.pretty_url:
response_body = json.loads(flow.response.content.decode("utf-8"))
# 定义JSONPath表达式:提取data.list中的所有id
jsonpath_expr = parse("$.data.list[*].id")
# 提取数据
order_ids = [match.value for match in jsonpath_expr.find(response_body)]
print(f"提取的订单ID:{order_ids}")
2. 多脚本组合使用
mitmdump支持同时加载多个脚本,按顺序执行:
python
mitmdump -p 8080 -s script1.py -s script2.py -s script3.py
适合将不同功能拆分到不同脚本中,便于维护。
3. 忽略特定域名,提升性能
当抓包时不需要处理某些域名(如广告、统计域名),可忽略以提升性能:
python
from mitmproxy import http
def request(flow: http.HTTPFlow) -> None:
# 忽略google-analytics和baidu统计的请求
if "google-analytics.com" in flow.request.pretty_url or "hm.baidu.com" in flow.request.pretty_url:
# 终止请求,不转发到服务器
flow.kill()
4. 结合数据库存储抓包数据
将抓包的关键数据(如接口请求参数、响应结果)存储到MySQL/Redis中,便于后续分析:
python
import json
import pymysql
from mitmproxy import http
# 初始化数据库连接
def start() -> None:
global db_conn, cursor
db_conn = pymysql.connect(
host="localhost",
user="root",
password="123456",
database="mitm_data"
)
cursor = db_conn.cursor()
# 创建表
cursor.execute("""
CREATE TABLE IF NOT EXISTS api_requests (
id INT AUTO_INCREMENT PRIMARY KEY,
url VARCHAR(255) NOT NULL,
method VARCHAR(10) NOT NULL,
request_body TEXT,
response_body TEXT,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
db_conn.commit()
def response(flow: http.HTTPFlow) -> None:
# 过滤需要存储的接口
if "api.example.com" in flow.request.pretty_url:
# 提取数据
url = flow.request.pretty_url
method = flow.request.method
request_body = flow.request.content.decode("utf-8") if flow.request.content else ""
response_body = flow.response.content.decode("utf-8") if flow.response.content else ""
# 插入数据库
cursor.execute("""
INSERT INTO api_requests (url, method, request_body, response_body)
VALUES (%s, %s, %s, %s)
""", (url, method, request_body, response_body))
db_conn.commit()
print(f"数据已存入数据库:{url}")
# 结束时关闭数据库连接
def done() -> None:
cursor.close()
db_conn.close()
print("数据库连接已关闭")
5. mitmdump与CI/CD集成
将mitmdump的脚本作为接口测试的一部分,集成到Jenkins/GitLab CI中:
-
在CI环境中安装mitmdump和依赖库;
-
启动mitmdump并加载测试脚本,同时运行被测应用;
-
执行接口请求(如通过curl/requests);
-
捕获mitmdump的日志,判断断言是否通过;
-
根据结果输出测试报告。
六、注意事项与避坑指南
1. HTTPS抓包失败的常见原因
-
未安装或未信任CA证书;
-
客户端使用了证书固定(Certificate Pinning)技术(如部分APP会验证服务器证书的指纹,mitmdump的证书会被拒绝);
-
系统时间与证书有效期不匹配(需同步系统时间)。
2. 脚本执行顺序问题
-
多个脚本的
request和response函数按加载顺序执行; -
单个脚本中,若在
request函数中修改了请求,后续的脚本会看到修改后的请求。
3. 性能问题
-
当抓包数据量过大时,避免在脚本中执行耗时操作(如大量IO、复杂计算);
-
合理使用过滤规则,只处理需要的请求,减少不必要的开销。
4. 合法性问题
-
mitmdump仅用于合法的测试、调试、个人学习场景;
-
未经授权抓取他人网络请求、篡改数据属于违法行为,需遵守相关法律法规。
5. 大文件请求处理
- 对于大文件(如视频、大文件下载),mitmdump可能会占用大量内存,可通过
flow.response.stream流式处理,或直接忽略。
七、总结
mitmdump不仅是一款抓包工具,更是**网络请求自动化处理的平台**。通过命令行操作,我们可以快速完成抓包和数据保存;通过Python脚本,我们可以实现请求/响应的任意修改、数据自动存储、接口自动化测试等复杂功能。
其适用场景覆盖:
-
接口调试:快速修改参数和响应,验证不同场景的接口表现;
-
数据采集:自动抓取网页/APP的图片、接口数据并存储;
-
接口自动化测试:自动断言响应,集成到CI/CD流程;
-
安全测试:模拟请求篡改,检测接口的安全性;
-
APP调试:捕获手机APP的网络请求,定位接口问题。
随着技术的发展,我们还可以将mitmdump与大模型结合------比如让大模型解析响应数据并生成测试报告,或根据请求内容自动生成测试用例,进一步提升自动化处理的能力。掌握mitmdump,无疑会让你的网络请求处理工作效率翻倍!