有个同事让我讲一下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))
DNS基于UDP,DNS服务器用的端口号是53,知道AWS 亚马逊云的DNS 服务叫做 Route53 的原因了吧。
浏览器中的DNS 缓存
Chrome在 chrome://net-internals/#dns 查看
Firefox在 about:networking#dns 查看
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 请求包如上所示,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”