通过抓包工具Wireshark 理解HTTP 协议

有个同事让我讲一下HTTP 协议,我向他推荐了《HTTP 权威指南》这本书,同时也用wireshark 结合浏览器控制台讲了下,我觉得还是很容易理解的。

DNS Frame

先抓了下DNS 包,因为浏览器HTTP 请求时,会先进行域名解析,整个过程是这样的:

首先查浏览器自身DNS 缓存,如果没有就会查本地hosts 文件,如果hosts 文件中没有查到,则查操作系统DNS 缓存,如果OS DNS 缓存中都没有查到,就会请求DNS 服务器 – 发出一个DNS 协议数据包。

如果浏览器启用了DoH (另一篇文章:DNS over HTTPS Firefox设置DoH),就不会用DNS协议来作域名解析了,而是HTTPS,因为DNS 明文。

一个DNS Query (请求)和Response (响应)的数据包结构如下:

DNS Frame = Dst Mac地址: c0:d8:c6:c0:d8:c6 + Src Mac地址: 22:fb:95:22:fb:95 
          + IPV4(08:00), Src IP: 10.9.9.106, Dst IP: 10.198.1.1
          + UDP, Src 端口: 60048(3a:90端口2个字节), Dst 端口: 53(00:35)
          + [Domain Name System (query/response) 长度(00:32=50字节=84(Length)-14(Eth2)-20(IPV4))
Domain Name System Query Package

DNS基于UDP,DNS服务器用的端口号是53,知道AWS 亚马逊云的DNS 服务叫做 Route53 的原因了吧。

浏览器中的DNS 缓存

Chrome在 chrome://net-internals/#dns 查看
Firefox在 about:networking#dns 查看

Firefox DNS Cache

TCP Frame

TCP Frame = Dst Mac地址: c0:d8:c6:c0:d8:c6 + Src Mac地址: 22:fb:95:22:fb:95
          + IPV4(08:00), Src IP: 10.9.9.106, Dst IP: 222.79.66.132
          + TCP, Src 端口: 49733(c2:45), Dst 端口: 80(00:50), Seq: 1, Ack: 1, Len: 298
          + [TCP payload]

其中 [TCP payload] 可以是HTTP Request Package 或 HTTP Response Package

HTTP

HTTP Request Package

一个HTTP 请求包如上所示,TCP payload后的GET /ocsp-devid01/ME… 这些是ASCII编码。

HTTP 请求 Package:

[Request Method] [Request URI] [Request Version]\r\n[Request Headers]\r\n[Request File Data]

HTTP 响应 Package:

[Request Version] [Status Code]\r\n[Response Headers]\r\n[Response File Data]
  • [Request Method] 的值如 GET/POST/HEAD…
  • [Request URI] 的值如 /?p1=2
  • [Request Version] 的值如 HTTP/1.1
  • [Request/Response Headers] 中会包含’Cookies’ 信息, 也会包含自定义的参数’Auth-Code’等
  • [Status Code] 的值有’200 OK’ 或’401 Unauthorized’ 或 ‘404 NOT FOUND’
  • [Request File Data]或者[Request Body]的值有以下类型:
    • form-data
    • raw[json]
    • application/x-www-form-urlencoded
  • [Response File Data]或者[Response Body] 的值可能是html/js/css等文本也可能是压缩的gzip 二进制流或gif/png/jpg的图片二进制流, HEAD 请求不会返回[Response File Data]

form-data: 如上传图片

[Request File Data] 的值如下:
------WebKitFormBoundary7MA4YWxkTrZu0gW\\r\\nContent-Disposition: form-data; name="file"; fileName="file.png"\\r\\nContent-type: image/png\\r\\n\\r\\n[图片文件二进制流]\\r\\n------WebKitFormBoundary7MA4YWxkTrZu0gW--\\r\\n
[Request Header] 中会包含有Content-Type:
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW\\r\\n

raw[json]:

[Request File Data] 的值如下:
{"k1":"v1","k2":"v2"}
[Request Header] 中会包含有Content-Type:
application/json;charset=UTF-8\\r\\n

application/x-www-form-urlencoded(和放在URL中的queryString是一样的格式):

[Request File Data] 的值如下:
k1=v1&k2=v2
[Request Header] 中会包含有Content-Type:
Content-Type: application/x-www-form-urlencoded\\r\\n

HTTP 请求的参数可以存在于URI 的PATH 和QUERY 中,也可以放在ResponseHeader(包括Cookie)/ResponseBody 中。

Wireshark 的使用

Capture Filter: 捕获前的过滤设置

上面tcp port 80 and host 45.32.131.193 表示只抓 45.32.131.193 这个服务器上的80端口包。
上面Loopback:lo0 表示本地间的通信,比如访问127.0.0.1,windows版wireshark 并不支持捕获Windows下本地间的通信,可以用 RawCap.exe。选择Loopback Pseudo-Interface,然后把截获的dumpfile.pcap文件用Wireshark打开。

RawCap.exe -s 30

捕获结果过滤

  • tcp.srcport ==80 && http &&ip.dst==192.168.10.174
  • tcp.port ==80 && http &&ip.dst==192.168.10.174
  • http.request.method == “POST”

Leave a Reply

Your email address will not be published. Required fields are marked *