在 Mac 中使用 wireshark 抓取网络包,近距离观察 HTTP 请求

Wireshark 与 HTTP 协议

一、前言

虽然是前端开发人员,对 HTTP 协议有些了解还是没有坏处的。

Windows 环境下有 Fiddler 可以很方便的拦截浏览器浏览器对 HTTP 请求进行分析、重放等功能,可惜目前没有 Mac 版本。我选择使用 Wireshark 来完成抓包。Wireshark 很强大,本文只用它来过滤 HTTP 请求用来分析。如果嫌麻烦可以使用 AlloyTeam 出品的 Rythem,很方便。

HTTP 协议,在 rfc2616 中详细定义了它的标准。但是如果不是要自己开发 web server 的话,也确实没必要也很难把它背下来烂熟于心。对于这种标准,有时间时候多读读可以长姿势,但是更多的可能在辩论的时候更有用。

进入正题。

二、准备工作

1.安装 wireshark

直接用 brew install wireshark --with-qt 即可。(PS:编译这个东西的时候电脑会好热!)

其实编译的图形界面是又 QT 和 GTK 可选的,但我选了 QT,因为相对于 Gnome 来说我更喜欢看 KDE。虽然我推测在这里不管 QT 还是 GTK 出来的界面都是没差的。

2.前端代码

<form action="." method="post">
    <input type="text" name="normal">
    <button>Submit normal form</button>
</form>
<form action="." method="post" enctype="multipart/form-data">
    <input type="file" name="multipart">
    <button>Submit multipart form</button>
</form>
<button id="js-ajax-submit">Ajax Submit</button>
<button id="js-submit-json">Submit JSON</button>
<script src="http://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<script>
    $(function(){
        $('#js-ajax-submit').click(function(){
            $.ajax({
                url: '.',
                type: 'POST',
                data: {ajax: 123}
            });
        });
        $('#js-submit-json').click(function(){
            $.ajax({
                url: '.',
                type: 'POST',
                contentType: 'application/json; charset=UTF-8',
                data: {ajax: 123}
            });
        });
    });
</script>

3.后端

直接用 python 的 SimpleHTTPServer 就好了。

三、开始

运行 sudo wireshark-qt。因为是要直接去读网卡的,所以必须要有 root 权限,不然什么都截不到。

打开之后的界面如图: wireshark main window

在监听之前需要先将本地 web 服务的端口添加进 wireshark 的 HTTP 协议监听的端口列表中,不然 wireshark 会将 HTTP 默认成普通的 TCP 连接。设置方法:

Edit -> Preferences -> Protocols -> HTTP -> TCP Ports: [add your port to this list]

这里我们需要选择监听最后一项本地回环,因为 web 服务是跑在本地的,流量不会出网卡。选中之后就进入了监听界面了:

capture-window

我们在最上方加了一个 HTTP filter,只查看 HTTP请求。

四、截图

普通 HTTP 表单 POST:
Multipart HTTP 表单 POST:
jQuery 默认 Ajax 请求:
提交 JSON 数据:

五、分析

从图中可以清晰的看出 HTTP 请求的格式。由于没学过计算机之前一直不理解 TCP 与 HTTP 之间的关系,后来慢慢懂了,所谓 HTTP 其实就是按照 TCP 三次握手的形式,将字符串按照一定的格式打包发送,就成了 HTTP。这也就是为什么 TCP 在传输层,HTTP 在应用层的解释吧。这也就是所谓「协议」了。

在 multipart 表单提交中仔细观察发现,其实请求的 header 和 body 是符合 rfc2388 的。如果要模拟浏览器上传文件到 web 服务器的话,实现这个协议就好了。

最后两张图,全部是用 Ajax 提交请求的。出于兼容性考虑,jQuey 默认的请求头是跟正常表单提交一样的(倒数第二张图),如果我们修改请求头部的 content-type,就成了倒数第一长图。可以看到请求的 body 已经从 form data 变成了 line-based text。这时候 web 服务器就没办法像处理表单那样直接处理这个请求了,需要按照头部指定的 content-type(json)来处理 body。这就是纯粹的 ajax + json 方式的前后端数据传递了。在 Flask 的源码中也可以看到,在 Request 对象中封装了 get_json() 方法,如果发现请求的 mimetype 是 json 格式的话,就可以通过直接调用这个方法来将请求的 body 转换成 json 数据返回。

六、后话

其实抓包的实现很简单,没事的时候抓抓包,就可以透过表象看清 WEB 请求运作的实质。抓包在安全领域的地位也很重要,比如媒体常常拿局域网嗅探来炒作无线热点的安全问题。有些事情看似复杂,其实原理都很好理解。就比如最近的好莱坞艳照门事件,如果真的像网友说的那样是用脚本跑出来的密码,那真的是技术含量很低。不过这恰恰也说明,重要的东西绝不是技术,而是技术到底能干什么和干了什么。

comments powered by Disqus