mitmproxy、mitmweb 与 mitmdump 自动化抓包手册
三个入口共享核心,但承担不同工作
mitmproxy 发行里有三个常用入口。mitmproxy 是终端交互界面,适合在键盘驱动的 flow 列表中观察与编辑;mitmweb 使用同一代理核心并提供浏览器界面;mitmdump 面向非交互日志、保存和 addon 自动化。它们读取同一套 options 和 ~/.mitmproxy/config.yaml,却有不同的展示与生命周期,脚本或 CI 应明确使用 mitmdump,不能把桌面交互会话假装成稳定任务。
macOS 官方推荐 Homebrew cask,Windows 使用官方安装器,Linux 优先官方独立二进制。需要额外 Python 依赖的 addon 时,再考虑 uv tool install mitmproxy,避免把系统 Python、发行包与独立二进制混在同一 PATH。安装后先证明三个命令来自同一发行:
mitmproxy --version
mitmweb --version
mitmdump --versionmitmproxy --version 的版本、Python 与 OpenSSL 信息应进入排障记录。官方预编译包冻结了随发行交付的 Python、OpenSSL 和其他依赖,也不会主动联网检查更新;团队要自己建立升级节奏和回归样例。下游 Linux 发行包可能落后,遇到行为差异时先比较真实二进制来源,不用“系统已经是最新”替代版本证据。
先以回环地址启动 regular proxy:
mitmweb --listen-host 127.0.0.1 --listen-port 8080另一个终端显式请求 HTTP:
curl --proxy http://127.0.0.1:8080 http://example.com/ \
-o /dev/null -w '%{http_code}\n'curl 状态码与 flow 同时出现,证明客户端到代理和代理到上游的基础链路成立。连接拒绝指向进程、监听地址或端口;flow 有请求却没有响应才继续检查代理主机 DNS、出口和上游。regular proxy 默认端口是 8080,但显式指定能避免配置文件、旧进程和多实例造成误判。
CA 目录同时是配置状态和高价值秘密
首次运行会在 ~/.mitmproxy 生成唯一 CA。mitmproxy-ca.pem 同时包含证书与私钥,不能交给客户端,也不能进入仓库、工单或备份共享;多数非 Windows 客户端只需要 mitmproxy-ca-cert.pem,Windows 可使用 PKCS#12 文件,部分 Android 流程使用 .cer。访问 mitm.it 可以按设备下载公开 CA 证书,但前提是设备已经正确连接到当前代理。
一次命令行实验可以只为当前 curl 信任 CA:
curl --proxy http://127.0.0.1:8080 \
--cacert "$HOME/.mitmproxy/mitmproxy-ca-cert.pem" \
https://api.example.test/health \
-H 'X-Debug-Case: mitmproxy-baseline' \
-o /dev/null -w '%{http_code}\n'flow 中应出现解密后的请求,服务端日志出现相同调试标识。去掉 --cacert 后,未安装该 CA 的客户端应报证书不受信;重新加回后恢复成功。这一对照把“代理可达”和“客户端信任代理 CA”分开。若应用启用了 certificate pinning,应优先使用自有 debug build、服务端日志或 trace;官方提供的 ignore_hosts 可让不需要观察的 pinned 域名只转发而不拦截。
mitmproxy 默认会先连接上游,读取真实证书的 CN、组织和 SAN,再动态生成拦截证书。上游证书验证仍然重要。ssl_insecure=true 会跳过它,使代理自身容易接受错误身份;不要为了让 flow 变绿而全局启用。内网测试 CA 应通过 ssl_verify_upstream_trusted_ca 提供明确 PEM,而不是关闭验证。
confdir 决定配置、CA 和其他状态的位置。为一次隔离测试设置独立目录,可以避免污染个人长期 CA;目录删除前要先撤销客户端信任。自定义 confdir 若没有 CA 会自动生成一套新的,旧客户端不会自动信任它,这也是多台开发机“同名 mitmproxy 却证书不同”的正常原因。
config.yaml 与 --set 是同一 options 系统
三个工具共享 typed options。--options 输出当前二进制真正支持的完整选项和默认值,比复制网上旧配置更可靠;命令行 flags 多数只是底层 option 的别名,交互界面修改的也是运行时 options store。
mitmdump --options > mitmproxy-options.txt
mitmdump --set flow_detail=2 --set body_size_limit=2m稳定团队配置可以进入 ~/.mitmproxy/config.yaml,但口令、私钥路径和内部地址不应随模板提交。cert_passphrase 放在命令行会出现在进程列表,官方也建议在配置中提供;团队更稳妥的做法是由临时权限受控文件或秘密注入层生成本次配置,并在进程退出后销毁。
mode 不只支持 regular HTTP proxy,还包括 local、transparent、SOCKS5、reverse、upstream 和 WireGuard。每种模式改变客户端接入或上游路由,不应在不了解网络责任时切换。开发侧抓浏览器或手机通常从 regular 开始;代理链环境可能用 upstream,但要分别处理客户端到 mitmproxy 的 proxyauth 与 mitmproxy 到上游的 upstream_auth。两种认证的主体和凭证不相同。
离开回环地址时,block_global 默认阻止公共 IP 来源,但它不是完整认证策略。局域网接入还应限制监听网卡、主机防火墙和设备来源,并配置 proxyauth。proxyauth 支持固定用户口令、htpasswd 或 LDAP 等形式;真实凭证不进入 shell history。任务结束恢复回环监听并撤销防火墙规则。
flow filter 决定处理对象,不决定调试授权
mitmproxy 的 flow filter 可按域名、URL、method、状态等条件筛选。末尾过滤表达式会限制交互视图或处理目标,save_stream_filter 决定哪些 flow 写入文件。它能减少数据量,却不能把未授权流量变成可抓取对象。
install -d -m 0700 captures
mitmdump \
--listen-host 127.0.0.1 \
--listen-port 8080 \
--set save_stream_file=captures/api.flow \
--set 'save_stream_filter=~d api.example.test & ~u /health' \
'~d api.example.test'保存文件是 mitmproxy flow,不是普通日志。它可能包含完整 headers、cookies、body、内部域名和二进制内容。过滤只选 host 仍可能收进该 host 下的登录、上传或个人数据;应再用固定 path、method 与调试标识缩小,并使用合成账号。HAR 的 hardump 会在退出时保存所有 flow,且 mitmdump 启用后需要把 flow 保留在内存,长时间任务容易同时扩大内存和磁盘。
大 body 可以用 body_size_limit 拒绝超过上限的内容,或用 stream_large_bodies 直接流向客户端。流式 body 默认不会被存储,也无法再修改;打开 store_streamed_bodies 会重新增加内存消耗。决定这些参数时先回答是要观察元数据、保存内容还是改写内容,不能三项都默认开启。
addon 把一次改写变成可审查代码
addon 通过事件 hook 接收 HTTPFlow 等对象,可以观察、阻断、改写和生成响应。下面的脚本只对测试 host、固定 path 和调试头生效,用来验证客户端对 503 的处理:
from mitmproxy import http
def request(flow: http.HTTPFlow) -> None:
if (
flow.request.pretty_host == "api.example.test"
and flow.request.path == "/health"
and flow.request.headers.get("X-Debug-Case") == "mitmproxy-503"
):
flow.response = http.Response.make(
503,
b'{"code":"UPSTREAM_UNAVAILABLE"}',
{"Content-Type": "application/json", "X-Debug-Proxy": "mitmproxy"},
)mitmdump --listen-host 127.0.0.1 --listen-port 8080 -s force_503.py客户端收到 503 与 X-Debug-Proxy,服务端没有该调试请求,证明 addon 在上游前短路。移除调试头后请求重新到达服务端,构成退出反证。若脚本只按域名匹配,开发机上其他请求也可能被改写;若异常未捕获,代理失败又可能被误认为业务故障。
进入仓库的 addon 应有依赖锁、静态检查和正反测试,配置用显式 option 注入。第三方 addon 与其 Python 依赖拥有读取和修改全部 flow 的能力,安装来源与代码审查应按高权限调试工具处理。多文件夹具要给出启动探针、最大运行时间、收到预期 flow 的成功条件和 finally 清理。
replay 先冻结匹配语义
client replay 把保存的请求再次发往上游,server replay 用保存响应回答匹配的新请求。两者不是浏览器级行为回放:认证、时钟、随机 ID、Cookie、环境和副作用不会自动合理化。重放写请求前应替换身份、确认幂等性并准备数据清理。
server replay 默认按请求寻找 flow,并会消耗匹配项;server_replay_reuse 可以重复使用同一响应。忽略 host、port、body 或参数会扩大匹配,可能把不相关请求答成旧响应。团队夹具应明确哪些 header 和参数参与身份,未匹配请求是 forward、kill 还是返回固定错误。默认 forward 会把漏匹配请求送到真实上游,离线测试若要求绝不出网,应改成明确阻断并用网络反证验证。
connection_strategy=lazy 可以推迟上游连接,便于离线 server replay;eager 更适合协议探测和镜像 TLS ALPN。策略改变连接时机,也会改变日志和失败位置。回放结果必须写出实际 strategy、匹配规则与额外请求处理方式,否则“本地重放通过”无法重现。
CI 里的 mitmdump 必须像临时服务一样被回收
CI 中先创建权限受限的临时 confdir 与输出目录,启动 mitmdump 后轮询监听端口或专用健康请求,探针通过才运行测试。进程要有限时、磁盘上限和可区分的退出码;测试结束无论成功失败都发送终止信号、等待进程退出、清除代理环境变量并删除 CA 私钥和 flow。
失败语义至少区分代理未启动、客户端未连接、TLS 未解密、addon 未命中、上游失败和业务断言失败。只让测试等待到超时,会把所有层次压成一个红灯。日志中禁止打印 Authorization、Cookie、完整 body 和代理认证口令;保存 flow 之前先执行过滤和脱敏,制品上传再做二次审查。
升级 mitmproxy 后使用同一组 HTTP、受信 HTTPS、不受信 CA、addon 短路、大 body、WebSocket 和退出清理样例回归。二进制内含冻结依赖且不会主动检查更新,长期钉死旧版与每次都追最新同样不可取;按安全修复、协议兼容和夹具稳定性决定升级窗口。
删除 CA 之前先证明没有客户端继续依赖
停止 addon、replay 和保存任务,再解除客户端代理。若 CA 被导入系统、浏览器、设备或 JDK,分别从对应信任库删除;删除 ~/.mitmproxy 只清除了本机私钥和配置,不会撤销其他设备已经安装的公开根证书。清理 flow、HAR、脚本临时文件和含秘密的 config,最后关闭监听和防火墙例外。
直连测试服务应成功,显式连接关闭后的代理端口应失败;证书库不再找到 mitmproxy CA;~/.mitmproxy 若保留,只包含经过审查的长期配置;临时 confdir、flow 和 addon 不存在。下次启动生成新 CA 后,旧客户端应出现可解释的不受信错误,这恰好证明旧信任没有悄悄跟随。
需要键盘交互和自动化脚本时,mitmproxy 的优势很明显;代价是团队承担 Python addon、配置、进程、流文件与 CA 生命周期。桌面 Map/Rewrite 和移动端引导更适合 Charles,跨平台 GUI 与 Rules/Composer 协作更适合 Fiddler。无论选哪一个,代理捕获都只服务获准测试流量,不能代替服务端可观测性和正式安全审计平台。
