[譯] 那些我們不需要的 HTTP 頭資訊

Uncho發表於2019-02-28

如果你想了解更多 http 頭資訊的知識,請關注 5 月 22 號安德魯在倫敦的演講

http 頭資訊是控制快取和瀏覽器處理web內容的一種重要方式。但很多時候它都被錯誤或冗餘地使用,這不僅沒有達成我們的使用目的,還增加了載入頁面時的執行開銷。這篇 http 頭資訊的系列博文中的第一篇文章,讓我們先來扒一扒那些不必要的 http 頭資訊。

大多數開發者都瞭解一些 HTTP 頭資訊,並利用它去處理內容。如大家熟知的 Content-TypeContent-Length,它們都是通用的。但最近,Content-Security-PolicyStrict-Transport-Security 這樣的頭資訊已經開始用於提高安全性,Link rel=preload 用於提高效能。只是極少數網站使用他們,儘管它們被瀏覽器廣泛支援。

與此同時,還有很多以前就有並且灰常受歡迎的頭資訊是不實用的。我們可以使用 HTTP 存檔 來證實這一點。HTTP 存檔 是由 Fastly 贊助並由 Google 運營的專案,每個月使用 WebPageTest 載入 500,000 個網站並進行效能測試,結果公佈在 BigQuery

在 HTTP 存檔資料中,這裡列出了 30 個最受歡迎的響應頭資訊(基於存檔中大多數網站都處理的頭資訊進行統計的結果),並大致說說它們多有用:

Header name Requests Domains Status
date 48779277 535621 Required by protocol
content-type 47185627 533636 Usually required by browser
server 43057807 519663 Unnecessary
content-length 42388435 519118 Useful
last-modified 34424562 480294 Useful
cache-control 36490878 412943 Useful
etag 23620444 412370 Useful
content-encoding 16194121 409159 Required for compressed content
expires 29869228 360311 Unnecessary
x-powered-by 4883204 211409 Unnecessary
pragma 7641647 188784 Unnecessary
x-frame-options 3670032 105846 Unnecessary
access-control-allow-origin 11335681 103596 Useful
x-content-type-options 11071560 94590 Useful
link 1212329 87475 Useful
age 7401415 59242 Useful
x-cache 5275343 56889 Unnecessary
x-xss-protection 9773906 51810 Useful
strict-transport-security 4259121 51283 Useful
via 4020117 47102 Unnecessary
p3p 8282840 44308 Unnecessary
expect-ct 2685280 40465 Useful
content-language 334081 37927 Debatable
x-aspnet-version 676128 33473 Unnecessary
access-control-allow-credentials 2804382 30346 Useful
x-robots-tag 179177 24911 Not relevant to browsers
x-ua-compatible 489056 24811 Useful
access-control-allow-methods 1626129 20791 Useful
access-control-allow-headers 1205735 19120 Useful

我們這裡只關注那些不需要的頭資訊,以及說明為什麼不需要它們、該如何處理。

沒用的資訊(server, x-powered-by, via)

你可能為你伺服器軟體的選擇而驕傲,但是大多數人(使用者)對此並不關心。並且這些頭部資訊可能會導致你的敏感資訊洩漏進而使得你的網站受到攻擊。

Server: apache
X-Powered-By: PHP/5.1.1
Via: 1.1 varnish, 1.1 squid
複製程式碼

RFC7231 標準允許伺服器在響應中包含 Server 頭資訊,識別用於服務內容的伺服器軟體。最常見的是 “apache” 和 “nginx”。雖然它是允許的,也不是強制的,但是對開發者和終端使用者都沒有太多實在意義。然而,它是當今 web 上第三個最流行的 HTTP 響應頭。

X-Powered-By 是沒有在任何標準中定義卻很受歡迎的頭資訊,相似地,通常用於指出 web 伺服器後的應用軟體平臺。常見的值有 “ASP.net”,“PHP” 和 “Express”,實際上它們並不提供任何好處,還佔用空間。

更具爭議的應該是 Via,當新增到通過其傳遞的代理來識別代理的任何代理的響應時,RFC7230 規定它是必須的。代理主機名的時候他可能是有用的,但更多時候它像是一個通用識別符號,如 “vegur”,“varnish”,或 “squid”。刪除或者不設定這個頭資訊在技術上是違反規範的,但是沒有瀏覽器對它做任何事情,所以如果你想刪除它是沒問題的。

棄用的標準(P3P, Expires, X-Frame-Options)

另一類 http 頭資訊是那些在瀏覽器中有效果的,但不是(或者不再是)達成效果的最佳方式。

P3P: cp="this is not a p3p policy"
Expires: Thu, 01 Dec 1994 16:00:00 GMT
X-Frame-Options: SAMEORIGIN
複製程式碼

P3P 是個讓人好奇的東東。我對它不瞭解,甚至很好奇,它最常見的值居然是 “this is not a p3p policy”。那它是,還是不是啊?

這要追溯到試圖使機器可讀的隱私政策標準化,當時大家對於如何在瀏覽器中顯示資料存在分歧,並且只有一個瀏覽器實現了這個 http 頭資訊 — IE 瀏覽器。即使在 IE 瀏覽器中,P3P 也不會給使用者帶去任何視覺效果,它只需要在 iframe 中允許訪問第三方cookie。有些網站甚至設定了一個不符合標準的 P3P 規則,比如上面的一個,即使這樣做是不合法律規定的

不用說,讀取第三方 cookie 通常是不可取的,所以如果你打算不這樣做,你也不需要設定一個 P3P 頭資訊

Expires 受歡迎程度達到了不可思議的狀況,試想下這種情況,Cache-Control 被設定為 20 年後過期。如果 Cache-Control 頭資訊包含 max-age 指令,那麼在相同響應上的任何 Expires 頭資訊將被忽略。但是有大量網站同時設定了這兩個資訊,並且 Expires 頭資訊通常被設定為格林尼治時間 — Thu, 01 Dec 1994 16:00:00。很多人這樣做因為他們不希望網站內容被快取和複製,所以就從規範中複製這個例項日期來填充。

Screen Shot 2018-05-10 at 21.49.25

實際上我們沒必要這麼做。如果你設定了一個 Expires 頭資訊併為其設定了一個過往的時間,那麼你可以這麼設定,用來取代你之前的做法:

Cache-Control: no-cache, private
複製程式碼

一些稽核你網站的工具會讓你新增一個值為 “SAMEORIGIN” 的 X-Frame-Options 頭資訊。這告訴瀏覽器你拒絕被其他網站誣陷,這也是預防點選攻擊的一種常用手段。
然而,以下更一致的支援和更可靠的行為定義的方式,可以實現同樣的效果:

Content-Security-Policy: frame-ancestors `self`
複製程式碼

作為頭資訊(csp)的一部分,你還獲得其他好處(稍後會詳細介紹)。所以你現在可能沒有 X-Frame-Options 頭資訊。

除錯資料(X-ASPNet-Version, X-Cache)

令人驚訝的是,一些最常用的頭資訊都沒有任何標準。實際上,這意味著,成千上萬的網站似乎自發地同意以特定的方式使用特定的 http 頭資訊。

X-Cache: HIT
X-Request-ID: 45a336c7-1bd5-4a06-9647-c5aab6d5facf
X-ASPNet-Version: 3.2.32
X-AMZN-RequestID: 0d6e39e2-4ecb-11e8-9c2d-fa7ae01bbebc
複製程式碼

實際上,這些“未知”頭資訊並不是由網站開發人員獨立完成的。它們通常是受使用特定伺服器框架、軟體或特定供應商服務的人為因素的影響而形成的(在此示例中,最後一個頭資訊是常見的 AWS 頭資訊)。

特別地,X-Cache 實際是 Fastly 新增的(其他 CDN 也是這樣做的),其他一些與 Fastly 相關的頭資訊,如X-Cache-HitsX-Served-By。當啟用除錯時,我們新增更多頭資訊,如 Fastly-Debug-PathFastly-Debug-TTL

這些頭資訊無法被任何瀏覽器識別,刪除它們對網頁渲染沒有任何影響。但是,由於這些標題可能向開發人員提供有用的資訊,因此你或許要保留一些方法來告知開發者。

不能被正確識別(Pragma)

我沒料到會在 2018 年寫一篇關於“Pragma”頭的文章,但根據我們的 HTTP 存檔資料,它居然還排在了第 11 位。早在 1997 年,Pragma 就已經棄用了,它也從來沒有打算成為響應頭 —— 正如所指定的,它只有作為請求的一部分時才有意義。

Pragma: no-cache
複製程式碼

儘管如此,它作為一個響應頭是如此被廣泛使用,以至於一些瀏覽器也能識別它。現在,你的回應將傳遞一個能識別 Pragma 的快取,而不能識別 Cache-Control 的概率很小。如果你想確保某些東西沒有被快取,你只需要 Cache-Control: no-cache, private

非瀏覽器的(X-Robots-Tag)

排名前 30 的頭資訊中有一個是非瀏覽器的頭資訊。X-Robots-Tag 用於對付網路爬蟲,比如 Google 和 Bing 的機器人。因為它對瀏覽器沒有任何意義,所有你可以在需要應對爬蟲的時候才設定這個頭資訊。與此同時帶來的影響,可能是使得測試變得困難,或者是違反了搜尋引擎的服務條款。

Bugs

最後,值得一提的是簡單的錯誤。在一個請求中,Host 頭資訊存在是有道理的,但是如果它出現在響應中就說明很可能你的服務被錯誤地配置(我很想知道這是怎麼產生的)。儘管如此,上文提到的 HTTP 存檔還是有 68 個網域返回了 Host 的頭資訊。

刪除頭資訊

如果你的網站使用了 Fastly 的服務,那麼恭喜你,使用 VCL 是刪去頭資訊是很便捷的。你可能希望將真正有用的除錯資料保留到你的開發團隊中,但將其隱藏在公共使用者中,這很有意義,你可以通過檢測 cookie 或傳進來 HTTP 頭資訊來輕鬆實現:

unset resp.http.Server;
unset resp.http.X-Powered-By;
unset resp.http.X-Generator;

if (!req.http.Cookie:debug && !req.http.Debug) {
  unset resp.http.X-Amzn-RequestID;
  unset resp.http.X-Cache;
}
複製程式碼

在本系列的下一篇文章中,我將討論設定 HTTP 頭資訊的最佳做法,以及如何啟用它們。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章