先说我昨天刚经历的一件事:朋友接手了别人留下的接口对接代码,前端一直报 400,后端怎么查都说没收到合法参数。我说别猜了,把请求抓出来看一眼——他装上免费开源的 HTTP/HTTPS 抓包工具后,五秒钟就发现请求头里把版本号带错了字段。这种“一抓就破”的体验,正是抓包工具最值钱的地方。
很多人以为抓包是安全测试人员的专属技能,其实日常开发里它就像医生用的听诊器:前端要看自己发的请求到底长什么样,后端要看真实客户端传来的 body,App 开发者要确认手机上发的 HTTPS 请求有没有被运营商或网关偷偷改过,这些场景都离不开一个可信任、可复现的抓包手段。如果说浏览器控制台 F12 的 Network 面板是“温室里的观察窗”,那独立的抓包工具就是“野外的实时录像机”,它不挑客户端、不挑平台,能把你电脑或手机上的真实流量完整记录下来。
这篇文章不打算泛泛盘点几十个工具,而是想围绕“免费开源”这件事,把手上的选型逻辑、安装步骤、证书原理、移动端注意事项和日常容易踩的坑讲透。文章里会重点用到 mitmproxy 这套工具链,它是我用了多年后认为最适合开发场景的开源方案;同时也会聊到 Wireshark、Whistle、HttpToolkit 各自的分工,以及 HTTPS 到底是怎么被“透明化”的。
1. 抓包前必须理解的流量链路:从明文 HTTP 到加密 HTTPS
1.1 HTTP 明文时代为什么不需要“解密”
HTTP 协议本身是文本协议,请求行、请求头、请求体基本都是可以直接阅读的字符串。以最简单的 GET 请求为例,浏览器在访问一个普通网页时,实际往服务器写出去的内容大致是:
http复制GET /api/user?id=1024 HTTP/1.1
Host: api.example.com
User-Agent: Mozilla/5.0
Accept: application/json
这些内容如果走的是纯 HTTP,那么中途任何一台网络设备只要做了端口镜像或者流量复制,就能原样看到。这也是为什么很多老旧系统坚持用 HTTPS 的主要原因:明文传输不仅怕“被偷看”,更怕“被篡改”,因为中间人把响应内容改掉之后,客户端几乎是无法察觉的。
抓包工具在 HTTP 阶段的工作其实非常简单,它连“解密”都不需要做,只需要把经过的请求原样保存一份,再展示到界面上即可。所以如果你要调试的系统还停留在 HTTP 明文阶段,那任何一款抓包工具都能胜任,难点从来不在解密,而在“怎么让流量愿意从抓包工具面前经过”。
1.2 HTTPS 加密后,抓包工具靠什么“看见”内容
HTTPS 的本质是“HTTP over TLS”,也就是说, HTTP 报文在发出前会先被 TLS 层加密,到达服务器后再解密。TLS 握手的核心是协商对称密钥,而协商过程依赖证书体系来确认对方身份。在没有抓包工具介入的情况下,客户端会校验证书是否由受信任的 CA 签发、域名是否匹配、证书是否过期,任何一项不通过都会直接中止连接。
抓包工具的做法,是让自己成为客户端和服务器之间的“中间层”。它会生成一份自己的根证书,并引导你把这根根证书安装到操作系统的受信任证书列表里。当你访问 https://example.com 时,抓包工具先与 example.com 完成真实的 TLS 连接,拿到服务器内容;同时又以 example.com 的名义向你本地客户端出示一张由它自己根证书签发的“同名证书”。因为你已经信任了那根根证书,客户端会认为这张动态生成的证书是合法的,于是加密连接建立成功,之后的 HTTP 明文内容对抓包工具来说完全可见。
这个过程在专业术语里常被叫“中间人解密”,名字听起来有点吓人,但它在本地调试场景里就是常规操作。关键分界线在于:只有你主动在自己的系统里信任了抓包工具的根证书,解密才会生效;如果你不动证书,抓包工具对 HTTPS 流量和一个旁观者没有任何区别,拿到手的只有一串密文。
1.3 为什么“信任证书”这一步如此重要
我对新手说三个字:不要跳。很多人在教程里看到安装证书就一身冷汗,觉得会有安全风险,于是偷偷省掉,然后跑来问为什么抓不到 HTTPS。答案很简单:没有那纸证书,TLS 握手的第一个校验就过不去,客户端会直接报证书错误,流量根本无法建立连接,更别说看到正文了。
反过来也要注意:一旦你把自己的根证书加入系统信任区,就意味着系统会无条件信任由这个工具签发的所有站点证书。如果这台电脑上同时有别人在操作,对方完全可以利用这份信任去拆解你正在登录的银行、邮箱等敏感流量。合规的做法是:只在专门的调试环境、自己使用的设备上安装,调试结束后把根证书从系统信任区移除。这也是我在这类工具上反复强调的一条底线,抓包是开发者的手术刀,不是挂在公共服务器上的监听器。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 免费开源工具各有所长:一份按场景的选型对照
2.1 先把工具分成“真开源”和“免费但闭源”两张桌
标题强调“免费开源”,但市面上的免费工具其实分两类。一类是真正开放源代码的项目,比如 mitmproxy、Whistle、Wireshark、HttpToolkit;另一类是免费提供给个人用户但源码并不公开的软件,最典型的就是老牌的 Fiddler Classic,它免费,却不属于开源。选型时我习惯把“能不能看到源码、能不能改代码、能不能随意二次分发”作为第一道分水岭,因为开源意味着社区会持续审计,出问题你可以自己定位,也能在 CI/CD 里放心嵌入。
为了不让你被琳琅满目的官网晃花眼,我先把常用候选按“日常开发调试”的实际体验整理成一张表:
| 工具 | 许可证 | 平台 | 界面形态 | 最擅长的场景 | 使用深浅 |
|---|---|---|---|---|---|
| mitmproxy | MIT 开源 | Windows / macOS / Linux | 终端 + Web + 纯命令行三合一 | 自动化抓包、移动端、二次开发 | 进阶主力 |
| Whistle | MIT 开源 | 跨平台 | Web 管理面板 | 前端 mock、接口重定向、团队分享规则 | 前端友好 |
| HttpToolkit | 开源核心 | 跨平台 | 原生 GUI | 快速过滤、Android 自动接入 | 新手友好 |
| Wireshark | GPL 开源 | 跨平台 | 原生 GUI | 看 TCP/IP 底层、定位网络故障 | 网络排查 |
| Fiddler Classic | 免费闭源 | Windows | 原生 GUI | 老项目维护、Windows 桌面临时抓包 | 老牌工具 |
| Charles | 付费试用 | 跨平台 | 原生 GUI | 团队商业化使用 | 不推荐本篇重点 |
2.2 mitmproxy:能扛住复杂场景的主力选手
mitmproxy 是 Python 生态里最知名的 HTTP/HTTPS 抓包工具之一。它的“三件套”形态对开发极其友好:
mitmproxy:终端里运行的交互式界面,适合在 SSH 会话或服务器上直接观察实时流量;mitmweb:启动后自动打开浏览器管理界面,用鼠标就能看请求与响应,新手也能很快上手;mitmdump:无界面模式,配合 Python 脚本做自动化拦截、改写和日志记录。
我把它放第一推荐位,不是因为别的工具不好,而是它在“抓包、改包、脚本化”这三件事上都做得足够深。除了手动改包,你还能直接写 Python 函数处理每一笔请求;抓下来的数据可以导出成标准 HAR 文件;启动参数可以控制监听端口、过滤规则、证书模式,几乎能无缝嵌进本地测试流程。
2.3 Whistle 与 HttpToolkit:各解决一类“手感”问题
Whistle 是 Node.js 社区里一个很实用的开源工具,它的核心优势是“规则化”。调试前端时,如果想把某个接口临时指向本地开发服务、想给某个域名统一加请求头、想模拟网络延迟或返回假数据,这些操作在 Whistle 里往往只需要写一行规则。团队协作时还可以把规则导出给同事,对前端联调非常友好。
HttpToolkit 的核心优势是省心。它会在启动时自动跳过本机无关的系统流量,不会一打开就涌入几百条 Chrome 后台请求;在 Android 上它甚至能通过 ADB 自动把手机流量接入电脑,省去手动填 IP 和端口的步骤。对刚接触抓包的人说,这几乎是“零摩擦”的图形界面选择。
Wireshark 虽然也能看 HTTP 报文,但它本质上不是为业务调试设计的。它站在更底层的位置,能看见 TCP 握手、重传、DNS 查询、TLS ClientHello 这些网络细节。当你怀疑“不是应用层逻辑问题,而是连接根本没建立起来”的时候,回头用 Wireshark 做二次确认,往往比在 HTTP 工具里瞎猜有用得多。
2.4 我的个人组合建议
经过一段时间的使用,我的固定组合是:日常接口联调用 mitmproxy 的 Web 界面;写自动化脚本或要在 CI 里校验接口时用它的 Python API;遇到前端需要快速 mock 的场合开 Whistle;网络彻底断了或者怀疑是防火墙问题时再请出 Wireshark。工具没有绝对的最好,只有分工不同。如果你只能学一个,我建议先学 mitmproxy,因为一旦理解了它,再切去任何图形化工具,底层逻辑都是通用的。
3. 实战:用 mitmproxy 抓下电脑上的第一条 HTTPS 请求
3.1 安装与启动:先把监听端口跑起来
如果你是 Mac 用户且有 Homebrew,安装是最快的:
bash复制brew install mitmproxy
Windows 或 Linux 用户如果有 Python 3.9 以上环境,直接走 pip 也行:
bash复制pip install mitmproxy
Linux 下有些发行版也提供 apt 包,比如 sudo apt install mitmproxy,不过版本通常偏旧,个人更推荐 pip 安装,便于随时升级。
安装完成后,新手可以直接用 Web 界面形态:
bash复制mitmweb --listen-port 8080
启动成功后,终端会提示 Web 管理界面运行在 http://127.0.0.1:8081 上,浏览器会自动打开。而 8080 这个端口是留给客户端流量接入用的,两个端口不要搞混,这是很多新手第一次启动时最容易犯的错:明明 mitmweb 管理页面已经打开了,却不知道真正的数据流量该往哪里填。
3.2 让浏览器和系统流量“从监听端口路过”
抓包工具不是网卡上的窃听器,或者说普通开发者用的 HTTPS 抓包并不走旁路监听,而是走显式的流量转发。要让本机浏览器把 HTTP/HTTPS 流量送到 127.0.0.1:8080,需要在系统网络设置或浏览器设置里指定“手动接入点”。
以 macOS 为例,路径是:系统设置 → 网络 → 找到当前 Wi-Fi 或以太网 → 详细信息 → 接入配置,把方式从“关闭”改为“手动”,地址填 127.0.0.1,端口填 8080。Windows 下类似,在“设置 → 网络和 Internet → 手动配置接入”里填入 IP 和端口即可。
Chrome、Edge 这类浏览器默认跟随系统设置,改完系统配置后重新打开页面即可生效。Firefox 比较特殊,它使用自己的独立证书库和接入配置,需要在 Firefox 设置里搜索“网络设置”,然后在连接配置里同样指向 127.0.0.1:8080,否则你会发现 Chrome 能抓到的流量,Firefox 里完全没有。
3.3 证书安装:第一次访问 http://mitm.it
配置好接入之后,打开浏览器随便访问一个网站,大概率会看到证书不受信任的提示,这个现象是正常的,因为你还没安装 mitmproxy 的根证书。此时打开地址:
text复制http://mitm.it
这个地址是 mitmproxy 内置的证书分发页面,它会根据当前客户端的操作系统,自动展示对应的下载入口。站点证书分为 pem 格式、p12 格式等。macOS 上一般下载后双击打开,导入到系统钥匙串,然后在证书列表里把“信任”选项设置为“始终信任”;Windows 则是双击 pem/p12,在证书导入向导里选择“受信任的根证书颁发机构”;Linux 图形环境一般把 pem 复制到 /usr/local/share/ca-certificates/ 后执行 sudo update-ca-certificates 即可。
Android 与 iOS 的安装步骤略有差异,我会在下一章单独细说,这里先把 PC 端的流程说完整。
3.4 验证:看到第一条可读的 HTTPS 请求
证书安装完毕后,在刚才的浏览器里访问:
text复制https://httpbin.org/get?query=hello
此时回到 mitmweb 的管理界面,你会看到列表里出现一条 GET https://httpbin.org/get?query=hello 的请求记录。点开 Request 面板,能看到请求方法、路径、HTTP 版本和全部请求头;点开 Response 面板,能看到远程服务器返回的 JSON 明文。到这里,HTTPS 解密链路已经打通。
如果看到的记录仍然是一堆无法阅读的 TLS 密文,通常是证书没装进正确的信任库,或者浏览器还没重启。建议关掉所有浏览器进程重新打开再试一次,因为证书信任信息往往在浏览器启动时加载,不是即时刷新。
3.5 一个值得收藏的细节:清理时要恢复原设置
调试完以后,记得把系统网络设置里的手动接入方式改回关闭。这一步不恢复的话,有一半的人会抱怨“关了 mitmproxy 之后电脑上不了网了”——原因很简单,流量还在往早已关闭的 8080 端口送,自然没人接管。不是工具把网络搞坏了,是配置没还原。
4. 手机端抓包:证书安装顺序与 Android/iOS 的差异
4.1 手机接入电脑的通用配置
手机抓包和电脑抓包没有本质区别,只是流量入口从“本机网络设置”变成了“手机 Wi-Fi 设置”。前提条件有两条:手机和电脑连接同一个局域网,并且电脑的防火墙允许外部设备访问 8080 端口。很多人在电脑端怎么抓都正常,一换手机就连不上,绝大多数是防火墙没有放行监听端口。
电脑上可以通过 ifconfig(macOS/Linux)或 ipconfig(Windows)查看当前局域网 IP,例如电脑 IP 是 192.168.1.100,那么在手机的 Wi-Fi 设置里,把接入方式改为“手动”,地址填 192.168.1.100,端口填 8080。
之后在手机浏览器里访问 http://mitm.it,会看到 Android 和 iOS 各自的证书下载说明,按照对应平台安装即可。
4.2 Android 7.0 之后为什么经常解不开 App 的 HTTPS
这才是手机端最容易让新手崩溃的地方。Android 系统从 7.0 开始,默认不信任“用户安装的证书”,只信任“系统证书”和 App 自己配置的证书。普通用户在手机上安装 mitmproxy 证书,装的是用户证书仓库;对于面向较新系统的 App 来说,它发起 HTTPS 请求时根本不会信任这个仓库,于是你看到的仍然是 证书校验失败。
所以从 Android 7.0 起,“装了证书就能解所有 App 的 HTTPS”这个旧观念已经失效了。实际能成功解密的情况通常只有这么几类:
- 目标 App 是你在自己的开发环境编译出来的调试版本;
- App 的
networkSecurityConfig明确允许信任用户证书; - 目标 App 内部使用了系统 WebView 且 WebView 允许用户证书;
- 目标系统版本较老,或目标应用没有按新行为适配。
这也是我提醒“抓包要限定在自己有权限调试的对象身上”的主要原因之一:当一个 App 明确拒绝用户证书时,强解属于越界行为,正确做法是先用开发者模式或调试包确认目标应用是否允许,而不是在网上找各种绕过方案来攻克它。
倒是 Android 模拟器场景会更友好。部分模拟器镜像使用 userdebug 类型系统,能直接安装系统证书;自己打包的 debug 版 App 里配置允许用户证书也完全可控。如果你日常只需要验证自己 App 的请求,建议优先跑模拟器,不要硬磕真机。
4.3 iOS 的证书安装与额外开关
iOS 端的核心步骤也是先让 Safari 访问 http://mitm.it,下载描述文件并安装。但 iOS 比 Android 多一个隐藏很深的开关:安装完描述文件后,必须到“设置 → 通用 → 关于本机 → 证书信任设置”,找到 mitmproxy 的根证书,并把“完全信任”开关打开。
漏掉这个开关的典型表现是:证书安装时没有报错,但访问任何 HTTPS 页面都提示证书无效。我第一次在 iOS 上抓包时也卡了十几分钟,后来总结出一个固定口诀:先下载描述文件,再安装,再去证书信任设置里开总开关,最后回浏览器刷新。顺序反了或者少一步,结果都是失败。
与 Android 类似,iOS 14 之后的系统对 App 内流量也有严格限制。第三方 App 如果不开启调试开关,默认同样不会信任用户安装的描述文件证书。能顺利解密的主要是 Safari 流量、部分遵守系统代理通道的轻量应用,以及你自己打的调试包。
4.4 抓完立刻恢复:手机端的善后操作
很多人在手机端抓完包后忘记关掉 Wi-Fi 接入配置,结果就是手机所有网络请求全部失败。因为手机还在不断把流量发到电脑的 8080 端口,而电脑上的 mitmproxy 已经退出了,根本没人响应。
建议养成三个习惯:第一,手机端调试完毕,先把 Wi-Fi 的接入方式改回关闭;第二,顺手移除手机上测试用的描述文件或证书;第三,电脑端防火墙规则如果不是长期需要,也可以回收。这样既不会影响正常使用,也能降低别人拿到你调试设备后滥用证书的风险。
5. 抓包不只是“看”:过滤噪音、拦截改写与脚本自动化
5.1 过滤规则:从几百条请求里快速定位目标
启动了抓包之后,最大的痛苦往往不是抓不到,而是信息太多。浏览器后台的埋点、自动更新的请求、各种统计脚本可能一秒钟刷出几十条记录。mitmproxy 的过滤表达式这时候就非常管用。在 mitmweb 上方的过滤框,或在 mitmproxy 命令行界面按 f 进入过滤设置,都可以直接写规则:
~u api.example.com:只看 URL 中包含 api.example.com 的记录;~m POST:只看 POST 方法;~c 400|404|500:只看状态码为 400、404 或 500 的记录;!~m GET:排除所有 GET 请求。
我调试接口时最常用的组合是 ~u /api/ & ~c 400,它能快速把所有失败的接口请求拎出来,然后逐个点开看请求头和请求体。很多时候后端报 400,本质上就是请求体格式不对或某个 Header 缺失,抓包界面里一对照就明白了。
5.2 手动拦截和改写:模拟各种边界条件
有些问题需要你主动构造异常请求来复现,比如把某个字段改成空值、把一个时间戳改成过期值。mitmproxy 提供了断点机制,你可以让指定请求在发出或响应返回前暂停下来,手动编辑后再放行。
在 mitmproxy 交互界面中输入:
text复制set intercept ~u login
之后所有 URL 里带 login 的请求都会被拦下。按 Enter 查看请求详情,按 e 进入编辑模式,可以改请求行、请求头或请求体;编辑完成后按 a 恢复放行。同理,如果你在流列表里看到某个响应,也可以在响应暂停时修改返回给客户端的 JSON。做前端联调时,这个功能可以用来模拟后端各种极端响应,不需要真的去改动后端代码。
5.3 Python 脚本:把抓包变成自动化测试的一部分
mitmproxy 最吸引我的一点,是它的“外挂脚本”能力。你可以用 Python 写一个文件,导出 addons 列表,然后让 mitmdump 在每次请求或响应时调用你的函数。举个例子,我想自动记录所有登录相关请求:
python复制import mitmproxy.http
class LoginRecorder:
def request(self, flow: mitmproxy.http.HTTPFlow) -> None:
if "login" in flow.request.pretty_url:
with open("login_flow.txt", "a", encoding="utf-8") as f:
f.write(flow.request.get_text() + "\n")
addons = [LoginRecorder()]
运行时指定脚本路径即可:
bash复制mitmdump -s recorder.py --listen-port 8080
更常用的场景是 mock 响应。假设前端需要测试“用户已是 VIP”的界面效果,而真实后端还没有返回 VIP 字段,你可以在测试环境里挂一个脚本,把某个接口的响应整体替换:
python复制from mitmproxy import http
def response(flow: http.HTTPFlow) -> None:
if "api/user" in flow.request.pretty_url:
flow.response.set_text('{"name": "mock-user", "vip": true}')
addons = [response]
加上响应改写之后,前端无需改任何请求代码就能看到 VIP 效果,也不影响后端真实逻辑。这种能力让抓包工具从“查看器”变成了“本地实验台”。
5.4 导出 HAR:把现场分享给队友
每次排查完问题,要把原始请求发给后端或者记录到工单里时,直接截图往往信息不全。更标准的方式是导出 HAR 文件。HAR 是 HTTP Archive 的缩写,几乎所有主流抓包工具都支持导出,Chrome DevTools 也支持导入,可以说已经成了 HTTP 请求记录的通用格式。
在 mitmweb 里,选择目标 Flow 后可以通过文件菜单将记录保存为 .har 格式;Whistle 和 HttpToolkit 也有类似的导出入口。拿到 HAR 文件的同事不需要安装任何抓包工具,直接拖进 Chrome DevTools 的 Network 面板就能完整复现请求头、响应体和时间线。这一点在远程协作时特别省口水。
6. HTTPS 解不开时的排查路线图
6.1 先分清是“没抓到”还是“抓到但解不开”
我在社区里见过很多朋友发帖说“mitmproxy 抓不到 HTTPS”,点开截图才发现,工具里明明能看到这条连接,只是响应体内容显示为乱码或直接标记了 TLS 错误。这两种情况要分开处理。
如果列表里非常干净,连请求记录都没有,说明流量根本没有经过监听端口。优先检查接入配置是否生效、浏览器是否走了独立接入设置、手机是否还在使用旧配置。如果能看到请求但打不开明文,则说明证书链路出了问题。按概率排序,第一是根证书没有安装到系统信任区,第二是安装后没有开启完整信任开关(尤其 iOS),
