📘 第六章 HTTP首部
📄 一句话概括

抓包时最常见的几个字段——Cookie、Set-Cookie、X-Frame-Options——都不在那 47 个里。 它们由别的规范定义,或者干脆是事实标准。

📝 本节和前面几节的关系

上一节把 HTTP/1.1 的 47 个列全了。但现实里天天打交道的几个字段不在其中,这一节把它们补上。

一、Cookie 家族:RFC 6265

Set-Cookie(服务端发)和 Cookie(客户端带回来)是今天最常用的两个字段, 却不在 HTTP/1.1 的清单里——它们由 RFC 6265 单独定义。 书里为它们单开了一节(6.7),这个安排本身就说明了问题:它们是事后补进 HTTP 的, 语义上不属于报文本身,而是属于状态管理。 这也解释了为什么 Cookie 的语法特别不整齐:Set-Cookie 用分号分隔一堆属性(Path、Domain、 Max-Age、HttpOnly、SameSite),Cookie 却只传键值对。 同一个东西两个方向两种格式,是历史遗留。

二、安全类:X- 开头的那些

书里 6.8 那四个都属于这一类: | 字段 | 作用 | 今天的状态 | |---|---|---| | X-Frame-Options | 禁止页面被 iframe 嵌套 | 仍广泛使用,CSP 的 frame-ancestors 是替代品 | | X-XSS-Protection | 开关浏览器的 XSS 过滤器 | 已废弃,现代浏览器移除 | | DNT | 请勿跟踪 | 没成为标准,几乎无人遵守 | | P3P | 隐私偏好平台 | 已废弃 | 这四个字段放一起看很有意思:四个里三个已经死了。 它们是 2013 年前后浏览器厂商各自试水隐私保护的产物,最后只有 X-Frame-Options 活下来, 并逐渐被 CSP 取代。 DNT 的死因特别值得记:它靠「网站自愿遵守」,没有强制力。 结果是广告商不遵守,遵守的网站也没得到任何好处,最后浏览器自己把它关掉了。

三、X- 前缀到底什么意思

按早年约定,X- 表示「这不是标准字段,别指望别人也认」。 但这条约定被滥用了——大量事实上成了标准的字段也带 X-,X-Forwarded-For、X-Requested-With、 X-Frame-Options 都是。 所以 2015 年的 RFC 6648 明确建议:别再新造 X- 开头的字段了。 要么走标准化,要么就用一个你能控制的独特前缀(比如厂商名)。 现实是老的还在用,新的也还有人加。 看到 X- 开头,正确的心态是「这可能只是某家的私有约定」,而不是「这一定是非标准」。

四、几个真正的新增字段

字段 规范 干什么
Strict-Transport-Security RFC 6797 让浏览器以后只走 HTTPS
Content-Security-Policy CSP 限制能加载哪些脚本、样式、图片
Forwarded RFC 7239 取代 X-Forwarded-For 这一族
Alt-Svc RFC 7838 告诉客户端同一资源还有别的入口
Alt-Svc 值得单独说一句:它是 HTTP/3 能落地的关键。
服务器先在 HTTP/1.1 或 HTTP/2 的响应里说「我这儿也支持 HTTP/3,在某个端口上」,浏览器记住,
下次直接试新协议。没有它,客户端根本不知道对方会不会说 QUIC。

五、动手 Demo:数一数这次往返里有多少个「书外」字段

先写死那 47 个字段名,再发一个带 Cookie、X-Forwarded-For、DNT 的请求, 看请求和响应里分别有几个字段不在这个集合里。

IN_47 = set(u'cache-control connection date pragma ... last-modified'.split())

print(u'请求里不在 47 个里的:')
for k in X.heads(r):
    if k.lower() not in IN_47:
        print(u'  ' + k)
print(u'响应里不在 47 个里的:')
for k in X.heads(out):
    if k.lower() not in IN_47:
        print(u'  ' + k)

实跑输出:

--------------------------------------------------------------------
不在那 47 个里的首部:Cookie 与安全类字段
--------------------------------------------------------------------
  这次请求带出去的首部里,有哪些不在那 47 个里:
    Cookie                   不在 47 个里
    X-Forwarded-For          不在 47 个里
    DNT                      不在 47 个里

  响应回来的:
    Set-Cookie               不在 47 个里
    X-Frame-Options          不在 47 个里
    Strict-Transport-Security 不在 47 个里

  服务端读到的 Cookie        SID=s01

  几个常见的「书外」字段:
  Set-Cookie                    RFC 6265                          服务端让客户端存 Cookie
  Cookie                        RFC 6265                          客户端把 Cookie 带回来
  X-Frame-Options               事实标准,后进 CSP                禁止被 iframe 嵌套
  X-XSS-Protection              已废弃                            早期浏览器的 XSS 过滤器开关
  DNT                           W3C 提案,未成为标准              请勿跟踪
  P3P                           W3C 已废弃                        隐私偏好平台
  X-Forwarded-For               事实标准,后由 Forwarded 取代     记客户端真实地址
  Strict-Transport-Security     RFC 6797                          强制后续走 HTTPS
  Content-Security-Policy       CSP 规范                          限制能加载哪些资源
  Alt-Svc                       RFC 7838                          告诉客户端「同一资源还有别的入口」

  HTTP/1.1 那份 47 个的清单只是「协议自己定义的」。
  现实中大量字段来自别的规范(Cookie、CSP、HSTS),
  或者干脆是事实标准(X-Forwarded-For、X-Frame-Options)。
  所以看到不认识的字段别慌,先查它是不是 X- 开头的自定义字段——
  按约定,X- 前缀表示「不是标准字段,别指望别人也认」。

请求里有三个:Cookie、X-Forwarded-For、DNT。 响应里也有三个:Set-Cookie、X-Frame-Options、Strict-Transport-Security。 总共六个字段,都不在那 47 个里,但它们在真实流量里出现的频率, 比 Max-Forwards 或 Content-MD5 高得多。 服务端读到了 SID=s01,说明 Cookie 那个字段是正常工作 的——「不在标准清单里」不等于「不管用」。 输出最后那张表列了十个常见「书外」字段和它们的出处,能看出来源很杂:RFC 6265、RFC 6797、CSP 规范、 还有两个是「事实标准」。

30 秒实验

  1. 给服务端加一条 Content-Security-Policy 响应首部,看它会不会被算进「书外」。
  2. 把 X-Forwarded-For 换成 Forwarded,对比两种写法的可读性。
  3. 想一想:为什么 DNT 会失败,而 Strict-Transport-Security 成功了?

常见误区

  1. 「不在 47 个里的就是非标准字段」——很多由别的 RFC 定义,甚至是正式标准。
  2. 「X- 开头的一定是私有字段」——大量 X- 字段事实上成了通用约定。
  3. 「新字段都该加 X- 前缀」——RFC 6648 明确建议不要这么做了。
自测三问(点开对答案) 1. `Cookie` 和 `Set-Cookie` 由哪个规范定义? —— RFC 6265。它们不在 HTTP/1.1 的那 47 个字段里。 2. 书里 6.8 那四个字段里,今天还有几个活着? —— 一个半。`X-Frame-Options` 还在用,正被 CSP 取代; `X-XSS-Protection` 和 `P3P` 已废弃,`DNT` 无人遵守。 3. RFC 6648 建议了什么? —— 不要再新造 X- 开头的字段名,因为它已经无法区分「私有」和「事实标准」了。

字段的清单和来源都清楚了。下一节讲一个更细的区分:哪些字段会被代理吃掉。

相关笔记