
抓包这件事我第一次认真做是在排查一个后台接口偶发超时的问题上。第一反应就是打开 Wireshark看 TCP 层到底发生了什么——是丢包重传还是服务端迟迟不回 ACK。后来这工具用得多了被问得最多的问题反而不是性能排查而是能不能看到网页登录时填的账号和密码。这个问题本身不复杂但它牵扯两层东西一层是 HTTP 协议到底怎么把表单传出去另一层是这件事该在什么范围内做。前者是纯技术后者是底线两个都得说清楚不然学一半很容易走歪。这篇我按自己的实操流程写先把边界和原理捋清再装工具再搭一个属于自己的测试站点然后一步步把包抓出来、把字段读出来顺手把 HTTPS 为什么抓不到讲透。适合刚接触 Wireshark 的人也适合做过开发但没系统看过协议层的朋友。全程用的都是我本机跑的服务和我自己填的测试账号没有第三方资产。1. 动手之前把边界和原理先捋清楚1.1 为什么这个实验值得做很多人觉得抓登录密码是个偏门技巧其实它的正身是协议分析。你把它当成一次协议观察练习收获会大得多你会真正理解表单数据在网络上长什么样、为什么现在的站点必须上加密、开发时哪些字段一旦明文传出去就等于裸奔。我在带新人时经常让他们做这个实验做完之后他们对前端做了校验就安全了这种想法会立刻打消。从实际工作角度看这项技能的迁移价值很高。接口联调时对方说我发了你没收到抓个包就能定位是请求没出去还是响应被吞了线上偶发超时看 TCP 层的重传和 RST 能迅速排除网络还是服务端问题甚至排查内网某个设备在偷偷发什么请求也靠它。学会读一个 POST 请求的每一个字段本质上就是学会了看懂机器之间的对话。所以这个实验的目标不是偷密码而是看懂一次完整的 HTTP 交互。密码只是这次交互里最容易识别的一个字段用它当抓手把整条链路串起来。1.2 只在你能完全控制的范围内动手这一条我必须放在所有技术内容前面因为越界和不越界之间没有模糊地带。安全的做法只有一种目标是你自己搭的服务或者你有明确书面授权的资产账号是你自己注册的测试账号数据是你自己填的假数据。只要这三条里有一条不满足这个实验就不该做。道理很实在。网络流量属于通信内容未经授权去捕获、解析、留存别人的通信内容性质跟翻别人抽屉没有区别。而且现实中这类行为的技术门槛极低正因为门槛低判断力才更重要。我见过有人拿同事的测试账号在办公网里抓包演示一下当场就把关系搞僵了因为对方不知道自己的登录信息被完整看到了。我的习惯是实验环境全部跑在本机回环地址或者我自己的虚拟机里不接公司内网不抓办公网任何一台别人的设备。这样即使抓到的东西包含凭据也是我自己填的test、abc12345这类假值没有任何真实信息泄露的风险。你在跟着做的时候也请把这条当成硬约束不要因为就试一下而松口。1.3 明文与加密这是整件事的技术分水岭为什么有的登录能被抓到密码有的完全抓不到答案就在协议是明文还是加密。HTTP 是纯文本协议请求头、请求体、URL 全部原样躺在 TCP 载荷里抓包工具读出来的就是可读字符。HTTPS 则是 HTTP 套在 TLS 之上TLS 在握手阶段协商出对称密钥之后所有应用数据都被加密成一段二进制密文抓包工具看到的只是应用数据这四个字内容无从还原。用一个生活类比HTTP 像寄明信片邮路上每个人都能看正面写的内容HTTPS 像把信纸塞进保险箱再寄箱子怎么运、多重、什么时候到路上都能观察但里面写什么只有收件人有钥匙。所以抓包工具能告诉你发生了一次对话、多大、什么时候但看不到对话内容。这也就解释了为什么现在几乎所有正经站点登录都是 HTTPS。而你如果在我搭的本地 HTTP 测试站上做实验就能看到完整的usernametestpasswordabc12345换成任何一个 HTTPS 站点你只会看到一串 TLS 记录什么都读不出来。这个对比本身就是这次实验最有价值的收获。2. Wireshark 从下载到能抓包安装与基础配置2.1 三个平台上的安装要点去官网下安装包是最省事的路子官方页面会根据你的系统自动推荐对应版本Windows 给 exemacOS 给 dmgLinux 各发行版也有自己的包管理器路径。版本上我个人建议用较新的稳定分支老版本对新的协议和显示过滤语法支持不全抓 TLS 1.3 的时候尤其明显。Windows 安装过程中有个关键环节安装程序会问要不要装 Npcap。这个东西是抓包的底层驱动不装的话 Wireshark 打开后网卡列表是空的什么都抓不到所以这个勾必须留着。它下面还有一个可选的 USBPcap只有你要抓 USB 设备通信时才需要普通网络抓包可以不装。另外建议勾上把当前用户加入抓包权限组否则每次启动都要弹管理员授权。macOS 上首次启动会提示需要安装权限辅助工具同意后系统会装一个后台组件让普通用户也能调用抓包接口装完重启 Wireshark 即可。Linux 下默认用普通用户跑dumpcap会因为权限不足失败常见处理是把当前用户加进 wireshark 用户组或者给 dumpcap 单独设置能力位两者都能解决我一般用加组的方式改完重新登录一次生效。2.2 网卡选择与混杂模式抓到包的第一道门槛打开 Wireshark 后主界面的网卡列表就是你所有能抓的网络接口。选哪块网卡决定你能看到什么流量物理网卡对应真实链路回环接口对应本机自己跟自己的通信虚拟网卡对应虚拟机或容器网络。做这次的登录实验如果服务跑在本机选回环接口最合适因为它会把本机发出的请求原样呈现出来干扰最小。混杂模式这个选项常被误解。它的作用是让网卡接收所有经过它的帧而不只是发给自己的帧。但它不等于能看到整个局域网的所有流量——在常见的交换网络里别人的单播流量压根不会送到你这块网卡上混杂模式也没用。想抓别人的流量需要网络设备层面的镜像或分光配置这属于运维范畴不是抓包软件能解决的。我踩过的一个坑是明明请求发出去了抓包界面一片空白。最后发现选错了网卡——浏览器走了另一块虚拟网卡。所以抓不到东西时第一件要做的事就是确认网卡选对了这个排查动作能解决一半以上的抓不到包问题。2.3 抓包过滤与显示过滤最容易搞混的两个概念这两个过滤器是新手最容易栽跟头的地方。抓包过滤器作用于抓取之前用的是 BPF 语法只能缩小抓什么而且一旦写错可能什么都抓不到显示过滤器作用于抓取之后用的是 Wireshark 自己的语法随时可改不丢数据。我的建议是抓包过滤器尽量少用或者不用除非流量特别大其余情况全交给显示过滤器因为原始数据留下来才是最重要的。两者的语法差别也很明显。抓包过滤器写host 192.168.1.10 and port 80用的是空格分隔的关键字显示过滤器写ip.addr 192.168.1.10 tcp.port 80用的是比较运算符和逻辑运算符。把写进抓包过滤器会直接报错这是我见过最多的低级失误。常用的显示过滤器我列几个高频的实测很好用用途显示过滤器写法只看 HTTP 请求http.request只看 POST 提交http.request.method POST锁定某台主机ip.addr 192.168.1.10锁定某个端口tcp.port 8000只看握手包tcp.flags.syn 1排除干扰流量!arp !icmp全文搜关键词frame contains password最后一条frame contains在排查某个字符串到底有没有发出去时特别顶用它直接在整帧的字节里匹配不依赖协议解析是否成功。2.4 长时间抓包怎么设置环形缓冲这是个很实际的问题长时间挂着抓包文件会以每分钟几十兆的速度膨胀硬盘很快见底内存也可能被拖垮。Wireshark 自带的环形缓冲就是为这个场景设计的。在抓包选项界面的输出标签页里勾上自动新建文件的选项再启用环形缓冲设定保留几个文件和每个文件多大超过数量的旧文件会被自动覆盖。我常用的配置是每个文件 50MB、保留 20 个这样总占用不超过 1GB能连续覆盖相当长一段时间的流量。如果你更关心时间而不是体积也可以设成每隔固定秒数换一个文件。另外有一个小开关值得注意就是实时更新数据包列表这个选项长时间抓包时建议关掉因为它会让界面不断重绘包量一大就卡得让人怀疑人生。还有一种更省资源的做法用命令行工具dumpcap在后台抓只写文件不渲染界面抓完之后再用 Wireshark 打开分析。我处理几个 G 的抓包文件时基本都走这条路效率高很多。3. 搭一个自己的测试站点实验环境怎么造3.1 最小可用Python 起一个能收 POST 的表单服务既然目标是自己可控的环境那第一步就是把站点搭起来。不需要什么框架Python 标准库就够了。下面这段代码跑起来后会在本机 8000 端口提供一个登录页面提交后把表单字段打印到终端from http.server import BaseHTTPRequestHandler, HTTPServer from urllib.parse import parse_qs, urlparse PAGE !doctype html htmlbody form methodpost action/login input nameusername placeholderusername input namepassword typepassword placeholderpassword button typesubmitlogin/button /form /body/html class Handler(BaseHTTPRequestHandler): def do_GET(self): if urlparse(self.path).path /: body PAGE.encode(utf-8) self.send_response(200) self.send_header(Content-Type, text/html; charsetutf-8) self.send_header(Content-Length, str(len(body))) self.end_headers() self.wfile.write(body) else: self.send_error(404) def do_POST(self): length int(self.headers.get(Content-Length, 0)) raw self.rfile.read(length).decode(utf-8) print(收到表单字段:, parse_qs(raw)) body bok self.send_response(200) self.send_header(Content-Type, text/plain) self.send_header(Content-Length, str(len(body))) self.end_headers() self.wfile.write(body) HTTPServer((127.0.0.1, 8000), Handler).serve_forever()保存成test_server.py然后python test_server.py跑起来浏览器访问本机 8000 端口就能看到表单。这个服务故意用了明文 HTTP就是为了让后面的抓包能看到完整内容。等你把明文这一遍走通了再把服务换成 HTTPS两组抓包结果一对比TLS 的作用就一目了然了。提示这个服务只监听回环地址只在本机可达不要改成对外监听再暴露到公网。测试服务不需要也不应该被外部访问。3.2 表单的三种提交姿势GET、POST 表单、POST JSON实际开发中登录请求有三种常见传法抓包时看到的形态完全不同值得逐一试一遍。第一种是 GET 提交。表单方法写成 GET浏览器会把字段拼到 URL 后面变成/login?usernametestpasswordabc12345。这种写法的特点是凭据出现在请求行里抓包一眼就能看到而且会留在浏览器历史、服务器访问日志里正规项目不会这么干但理解它有助于你读懂 URL 参数。第二种是 POST 表单提交也就是上面代码里的方式。字段放在请求体里编码类型是application/x-www-form-urlencoded内容是usernametestpasswordabc12345这样的键值对。这是最常见的传统写法抓包时在请求体里能看到明文。第三种是 POST JSON现代前后端分离项目的主流。编码类型是application/json请求体是一段 JSON{username:test,password:abc12345}。抓包看到的形式不同但明文程度是一样的。三种方式都试一遍你对数据到底放在报文的哪一段就会有肌肉记忆。后面看真实流量时扫一眼请求行和 Content-Type 就能判断该往哪儿找字段。3.3 把测试流程固定下来方便反复对照做这种实验最忌讳的是每次操作都不一样最后自己也说不清差异来自哪里。我的做法是把流程写成固定脚本清空浏览器缓存和 Cookie打开抓包访问页面填固定的一组假数据提交停止抓包保存文件。每次改一个变量比如只把 HTTP 换成 HTTPS或者只把 GET 换成 POST其余保持一致。固定流程还有个好处是可以留档。我会把每次抓包文件按日期-协议-提交方式命名存好比如20240601-http-post.pcapng。日后想复习 TLS 握手长什么样直接打开文件就行不用重新折腾环境。这种留证据的习惯在排查线上问题时同样适用抓到的包文件就是最硬的事实。数据方面用户名密码就用test和一段明显的假密码不要图省事复制自己的真实账号。这个习惯看着小其实是职业素养的一部分。4. 实战抓包从三次握手到表单字段4.1 第一步锁定流量别在一堆包里迷路环境准备好之后选回环网卡开始抓包然后浏览器访问http://127.0.0.1:8000/提交表单停止抓包。这时候数据包列表里会混着 DNS、ARP 之类的背景流量先在显示过滤器里输入tcp.port 8000瞬间就清爽了。你会看到这样一组包先是三次握手SYN、SYN/ACK、ACK 三条然后是浏览器发出的 GET 请求服务端返回的 200 响应紧接着浏览器又发起一组新的连接用于表单提交或者复用已有连接最后是 POST 请求和响应。每一条在列表里都有编号、时间、源地址、目的地址、协议和长度信息还有一列叫 Info写得比较人性化会直接告诉你这条是 GET 还是 POST。这里有个实用技巧把时间显示格式调成当日时间排查时序问题时比相对秒数直观得多在视图菜单的时间显示格式里就能改。另外如果你抓的是自己的机器源地址和目的地址都会是回环地址一眼就能认出来不用担心认错。4.2 第二步Follow Stream 看完整会话找到那条 Info 里写着 POST 的包右键选择 Follow再选 TCP Stream。Wireshark 会把这条 TCP 连接上双向传输的所有字节按顺序拼成一个窗口显示出来服务端到客户端的数据用红色显示客户端到服务端用蓝色显示。这个视图是理解一次完整会话最快的路径比一条条点包看省事得多。在这个窗口里你会看到完整的请求报文POST /login HTTP/1.1 Host: 127.0.0.1:8000 User-Agent: Mozilla/5.0 (...) Content-Type: application/x-www-form-urlencoded Content-Length: 32 Connection: keep-alive Upgrade-Insecure-Requests: 1 usernametestpasswordabc12345空行之前是请求头空行之后是请求体密码就在最后一行。到这里这次实验的核心目标就达成了。但别急着关掉窗口我建议你多花十分钟把每一个头部字段都读懂Host 告诉服务端请求的是哪个站Content-Type 说明请求体的编码方式Content-Length 是请求体的字节数User-Agent 暴露了客户端信息Cookie 头如果存在会被完整展示。这些字段每一个都有自己的用途理解了它们后面看任何 HTTP 流量都不再陌生。顺便说一句请求头里的 Cookie 常常比密码更值钱因为很多系统登录后靠 Session Cookie 维持身份。抓包时看到一整串 Cookie 明文滚过去那种直观冲击比看密码本身更让人警觉。4.3 第三步读懂 HTTP 请求里的每一个字段把请求报文逐段拆开能看到一些平时完全不会注意的细节。请求行由方法、路径、协议版本组成GET 会把参数塞进路径POST 不会Host 是虚拟主机的关键同一台服务器上的不同站点靠它区分Content-Length 决定了服务端读多少字节抓包里长度字段和实际体长度必须对得上对不上就说明报文被截断或者被篡改过。请求体部分application/x-www-form-urlencoded编码会对特殊字符做百分比转义所以你在抓包里看到的中文可能是%E4%B8%AD这种形式这不是乱码是编码。JSON 格式则保持原样中文能直接看到。理解这两种编码的差异排查乱码问题时就能对症下药。响应报文同样值得看。状态码 200 表示成功302 表示跳转401 表示未认证这些在初步排查时非常有用。响应头里的 Set-Cookie 如果你在做登录流程调试往往就是身份凭证的起点。把请求和响应合起来看一次会话的完整逻辑就浮出水面了。4.4 第四步HTTPS 为什么看不到——TLS 到底做了什么现在把测试服务换成 HTTPS或者直接对任意一个正常网站抓包你会在同一位置看到完全不同的东西协议列显示为 TLSInfo 里写着 Client Hello、Server Hello、Application Data 之类的字样。点进去看字节是一堆看似随机的二进制没有username没有password什么都没有。这不是抓包软件变弱了而是加密真的生效了。TLS 握手大致分几个阶段客户端发 Client Hello 声明支持的版本和密码套件服务端回 Server Hello 选定参数并送出自己的证书双方通过密钥交换算法各自算出同一份会话密钥之后所有应用数据用对称加密和完整性校验保护起来抓包看到的 Application Data 就是密文。证书里的公钥只用于协商无法反推出会话密钥。所以结论很明确对采用 HTTPS 的站点在网络层面抓包拿不到登录内容。你能观察到的只是通信元数据——谁和谁通信、什么时间、大概多大。这也正是现在各类客户端默认走加密的原因它把内容保护从应用自觉变成了协议强制。4.5 自己的应用要调试加密流量会话密钥日志的用法现实里确实有需要看加密内容的场景比如你在调自己写的一个 App怀疑它发的请求参数不对但走的是 HTTPS。这种情况下有个明确的、可控的做法让客户端把自己使用的 TLS 会话密钥记录到一个文件里再让 Wireshark 读取这个文件来解密。具体操作是设置一个叫SSLKEYLOGFILE的环境变量指向一个文件路径主流浏览器和不少开发库都支持这个约定启动后会把每次会话的密钥追加写入。然后在 Wireshark 的协议首选项里找到 TLS 项把主密钥日志文件名指到这个文件。之后重新抓包原本的 Application Data 就会被解密还原成可读的 HTTP 请求。必须说清楚三件事。第一这个机制的前提是客户端主动交出密钥本质上是自证自测不是破解。第二它只对你能控制的环境有效别人的会话密钥你拿不到。第三这个密钥文件极其敏感能解密你的全部会话用完立刻删除不要留档、不要外传。我用这个功能基本只在本地调试开发中的接口问题定位完就清掉。5. 常见问题排查实录5.1 抓不到包网卡列表空白或流量不出现网卡列表整个是空的九成是底层驱动没装好。Windows 上重装一遍并确认 Npcap 那一步没有被跳过Linux 上检查当前用户是否在抓包权限组里macOS 上确认首次启动时安装的后台组件授权有没有点同意。这类问题基本都能通过重装或者补权限解决。列表有网卡、但抓不到预期流量通常是选错了接口。我在同时开着虚拟机和容器的时候经常遇到浏览器的流量走了另一块网卡。解决方式是挨个试或者干脆把回环和物理网卡同时抓。还有一种情况是流量确实经过了但被抓包过滤器挡掉了这时候把抓包过滤器清空再看一遍往往立刻就有。最后一个容易忽略的点是浏览器缓存。第二次访问同一个页面时可能直接命中缓存压根不发请求自然抓不到。测试时养成按强制刷新或者先清缓存的习惯能省掉很多为什么没反应的困惑。5.2 界面卡死、打不开、崩溃Wireshark 拖慢甚至卡死最常见的原因是包量太大又开了实时更新或者在巨大的抓包文件上频繁改动显示过滤器。每敲一个字符它都要在上百万条记录里重新计算匹配硬件再好也扛不住。我的处理方式是大文件先关掉实时更新用命令行工具做第一轮筛选把结果导出成小文件再打开。命令行处理大文件的速度比图形界面快一个数量级。启动就报错打不开的情况多半是配置残留导致的。可以试着临时重命名用户配置目录让它重新生成默认配置如果这样能打开再把旧配置里的自定义项一点点搬回来。另外老旧版本和新系统之间的兼容问题也确实存在与其折腾不如直接换到较新的稳定版本。还有一种假卡死显示过滤器语法写错了界面顶部变红但也不提示得很明显看起来像没反应。养成写完过滤器看一眼顶部颜色条的习惯红色就说明语法有问题。5.3 包太多看不懂几个提速技巧抓包最大的心理门槛就是一屏幕的包不知道从哪看起。我的经验是先缩范围再深入先用端口或者 IP 把无关流量剔掉再用协议过滤只留 HTTP 或 TLS最后盯住一两条连接做深入分析。整个过程是漏斗形的不是一上来就想看懂全部。其次要善用着色规则。Wireshark 默认已经给不同状态打了颜色黑色底通常意味着问题包比如重传、乱序、连接重置。看到黑色条目优先点开看往往问题就藏在那儿。你也可以自定义着色规则把自己关心的特征标出来比如所有 POST 请求标成醒目的颜色。最后是善用统计功能。会话统计能一眼看出哪两条主机之间通信最多协议分级能告诉你各类协议占比流量图能直观展示吞吐随时间的变化。这些功能在排查到底是哪个环节慢的时候比逐包看高效得多。5.4 常见问题速查表现象常见原因处理方式网卡列表空白底层驱动缺失或权限不足重装驱动、补权限组、重启软件抓不到表单请求网卡选错、缓存命中、过滤器过严换接口重抓、强制刷新、清空过滤器只看到密文目标使用加密传输属正常现象加密内容无法从网络层还原界面极卡包量大且开启实时更新关实时更新改用命令行预筛颜色标黑重传、乱序或连接重置优先排查该条链路的两端状态中文显示异常编码未按 UTF-8 解析检查报文的字符编码设置时间显示不直观默认用了相对时间改为当日时间格式便于对时序这张表基本覆盖了我这些年被问到的绝大部分问题遇到卡壳时可以对照着排查。6. 站在防守方如果这站是你写的该做什么6.1 传输层全站加密与强制跳转做完这次实验最有价值的产出其实是反向思考如果这个站点是我负责的我该怎么设计才不让这种抓包看到任何东西答案的第一层是全站加密。不只是登录页加密全站所有页面、所有接口都应该走加密通道因为登录后的 Session 凭证明文传输同样致命。只加密登录页是个常见的误区。第二层是强制跳转和防止降级。服务端应该把明文请求直接跳转到加密地址同时启用相关的响应头告诉浏览器此后只走加密连接避免有人通过中间环节把用户引导回明文。浏览器端也有相应的安全机制可以配合形成双保险。第三层是避免在 URL 里放敏感信息。前面说过 GET 提交会让参数出现在请求行而请求行除了被抓包看到还会被记进服务端访问日志、浏览器历史、跳转来源头里。敏感字段一律走请求体这是最基本的要求。6.2 应用层敏感字段的收集与留存协议层之外应用层还有很多容易漏的地方。密码字段在前端要保证输入框类型正确避免明文回显提交后服务端要立刻做哈希处理绝对不能落库存明文日志里要过滤掉密码、令牌、身份证号这类字段很多泄露事故就是因为调试日志被带到了生产环境。还有就是响应内容要克制。登录失败时不要区分用户不存在和密码错误统一给一条模糊提示避免被用来枚举账号。返回的数据里只带前端需要的字段不要把整个用户对象连同敏感信息一起扔出去。这些看起来是安全设计的细节但它们的出发点跟这次抓包实验是同一个假设传输链路和客户端都不可信只把必须传的东西传出去。我在实际项目里推这套东西时最有效的方式不是讲规范而是拿一份真实的抓包文件给团队看。当大家亲眼看到自己写的登录请求里那行明文密码时对加密的接受度会瞬间拉满比开会讲十遍都管用。6.3 日志、监控与前端代码里的隐形泄露最后一类泄露常常被忽略。前端打包后的代码里如果硬编码了接口密钥或者测试账号浏览器开发者工具一打开就能看到抓包反而成了多此一举。运维侧的访问日志如果完整记录 URL 和请求体等于把所有凭据又抄了一份存在磁盘上。第三方统计脚本如果被允许读取表单内容同样是个大窟窿。我的做法是上线前用抓包工具自查一遍自己的站点看看有没有本不该明文出现的东西同时检查日志配置确认敏感字段被过滤再扫一遍前端产物里有没有可疑的硬编码字符串。这套自查流程花不了半小时但能堵住相当一部分低级问题。说到底抓包这个技能的价值不在于能看到什么而在于它逼着你从攻击者的视角审视自己的系统。你能不能看到别人的密码取决于对方有没有做好该做的事而对方能不能看到你的取决于你有没有。如果你跟着把这一整套跑完了我建议再做一个小扩展把测试服务换成加密版本再抓一次包把两份文件并排打开对照着看。同一套操作流程一个清清楚楚写着字段一个只有 TLS 记录那个对比带来的理解深度比读十篇协议文档都实在。我自己就是这么把这个知识点真正刻进脑子里的。