了解 HTTP/2 指紋的運作原理:SETTINGS 幀、視窗增量與偽標頭順序,以及 Akamai 指紋如何與 JA3/JA4 配合偵測機器人。
每一個 HTTPS 連線都先經歷 TCP 握手和 TLS 協商,但 HTTP/2 指紋識別並不在這兩個階段進行。HTTP/2 指紋識別捕獲的是客戶端在 TLS 建立之後——在 HTTP/2 工作階段開始的最初幾毫秒內,在任何請求發出之前——所傳送的幀的特徵。客戶端傳送的 SETTINGS 幀、流量控制增量和偽標頭順序的精確組合,由其 HTTP/2 實作決定,而非由使用者決定,並在請求之間保持一致。這種一致性,就是它成為指紋的原因。
核心重點
- HTTP/2 客戶端在發出第一個請求之前就已自我暴露。 初始 SETTINGS 幀、WINDOW_UPDATE 增量和 PRIORITY 幀由 HTTP/2 函式庫決定,而非由使用者決定,從而在 Chrome、Firefox、Safari 和自動化工具之間產生不同的特徵簽名。
- Akamai 指紋將四個訊號——SETTINGS 值、視窗增量、PRIORITY 幀和偽標頭順序——編碼為一個緊湊字串,用於識別底層 HTTP 客戶端。
- 它能捕獲通過了 TLS 和 User-Agent 檢查的機器人。 使用
curl-impersonate仿造 Chrome TLS 握手的腳本,通常仍然無法通過 HTTP/2 層的檢查,除非它還完整模擬了 Chrome 的幀序列和偽標頭順序。 - 與 JA3/JA4 配合使用,兩種指紋涵蓋互補的層:TLS 識別加密函式庫;HTTP/2 指紋識別 HTTP 實作。兩者之間的不一致是強烈的機器人訊號。
- PRIORITY 幀——歷史上 HTTP/2 指紋中最具辨識度的部分——已在 RFC 9113 中被廢棄,因此現代指紋更多地仰賴 SETTINGS 值和偽標頭順序。
HTTP/2 是什麼,為何會產生指紋?
HTTP/2(RFC 7540,由 RFC 9113 更新)以二進位分幀層取代了 HTTP/1.1 純文字、一次一個請求的模型。所有通訊透過帶編號的串流在單一 TCP 連線上進行,由二進位幀承載——每種幀都有類型:DATA、HEADERS、SETTINGS、WINDOW_UPDATE、PRIORITY 等。
當客戶端開啟一個 HTTP/2 連線時,它在能夠發出任何請求之前,會遵循規定的啟動序列:
- 傳送 HTTP/2 連線序言——一個固定的 24 位元組魔術字串。
- 傳送 SETTINGS 幀,宣告本次連線的客戶端參數選擇。
- 選擇性地傳送 WINDOW_UPDATE 幀,增大初始流量控制視窗。
- 選擇性地傳送 PRIORITY 幀,建立串流依賴樹。
- 傳送第一個攜帶實際 HTTP 請求的 HEADERS 幀。
步驟 2–4 發生在伺服器回應之前,也在任何使用者撰寫的程式碼執行之前。它們完全由 HTTP/2 函式庫決定——而且不同實作之間的差異在工作階段、URL 和 IP 位址間保持穩定。
Akamai 指紋捕獲的四個訊號
Akamai Technologies 的研究人員觀察到這些啟動訊號對每個客戶端來說足夠穩定,可以作為指紋使用。Akamai 指紋將四個訊號編碼為一個以垂直線分隔的字串。一個典型的指紋如下所示:
1:65536;3:1000;4:6291456;6:262144|15663105|0|m,a,s,p
1. SETTINGS 幀值
SETTINGS 幀是一個 參數ID:值 對的清單。HTTP/2 定義了六個標準參數:HEADER_TABLE_SIZE(ID 1)、ENABLE_PUSH(2)、MAX_CONCURRENT_STREAMS(3)、INITIAL_WINDOW_SIZE(4)、MAX_FRAME_SIZE(5)和 MAX_HEADER_LIST_SIZE(6)。客戶端只傳送它想覆蓋協定預設值的參數。
出現哪些參數、它們的值及其順序的組合由 HTTP/2 函式庫決定。Chrome 基於 BoringSSL 的 HTTP 堆疊選擇的值和順序,與 Firefox 的 Necko、Safari 的 CFNetwork 或 Python 的 httpx 不同。即使是微小的版本更新,也可能改變包含哪些參數或其攜帶的值。Akamai 指紋字串的第一段——上方範例中的 1:65536;3:1000;4:6291456;6:262144——就編碼了這些鍵值對。
2. WINDOW_UPDATE 增量
HTTP/2 的流量控制系統從預設連線層級視窗 65,535 位元組開始。大多數客戶端立即傳送一個 WINDOW_UPDATE 幀,將其增加到更大的工作大小,所選擇的具體增量是該客戶端的特徵。缺少 WINDOW_UPDATE 或不尋常的增量值本身就是一個訊號——許多精簡 HTTP 函式庫完全省略這一幀,而主流瀏覽器則傳送一個大的、函式庫特有的增量值。指紋的第二段編碼這一值。
3. PRIORITY 幀序列
HTTP/2 最初允許客戶端使用 PRIORITY 幀宣告串流優先順序,建立依賴樹,讓伺服器知道優先傳送哪些回應。瀏覽器傳送獨特的啟動模式:Chrome 的歷史模式包含針對串流 3、5、7、1 和 11 的特定 PRIORITY 幀序列,各有規定的權重。這些模式極為穩定,與通常完全省略 PRIORITY 幀的非瀏覽器 HTTP 客戶端截然不同。
RFC 9113(2022)廢棄了 HTTP/2 串流優先順序機制,因為實作起來很複雜且在實務中很少改善效能。現代客戶端越來越多地省略 PRIORITY 幀。Akamai 指紋的第三段捕獲這一模式(或其缺失),仍可區分較舊的瀏覽器版本與無頭或腳本化的 HTTP 客戶端。
4. 偽標頭順序
HTTP/2 請求將方法、路徑、協定方案和主機編碼為偽標頭——:method、:path、:scheme 和 :authority——在 HEADERS 幀中必須位於普通標頭之前。協定要求這四個偽標頭都出現在普通標頭之前,但彼此之間的順序由實作決定。
瀏覽器始終使用特定的順序。Chrome 通常傳送 :method、:authority、:scheme、:path——在指紋中編碼為 m,a,s,p。Go、Python 和 Node.js 中的 HTTP 函式庫通常按不同順序發出這些偽標頭,或者順序因版本而異。第四段捕獲這一順序,結合 SETTINGS 訊號,它是區分真實瀏覽器客戶端與自動化函式庫最穩定的指標之一。
HTTP/2 指紋如何與 TLS 指紋互補
TLS 指紋識別(JA3/JA4)從 ClientHello 訊息中提取簽名——該訊息在 TLS 工作階段加密之前以明文傳送。HTTP/2 指紋識別則從 TLS 建立後立即傳送的二進位幀中提取簽名。兩者在相鄰層上運作,互無重疊:
| 層 | 技術 | 捕獲內容 |
|---|---|---|
| TLS | JA3 / JA4 | ClientHello 中的密碼套件、延伸、橢圓曲線 |
| HTTP/2 | Akamai 指紋 | SETTINGS 值、視窗增量、PRIORITY 序列、偽標頭順序 |
成功使用 curl-impersonate 等工具複製 Chrome TLS 握手的機器人,仍然會從其底層 HTTP 函式庫傳送 HTTP/2 幀——不同的 SETTINGS 集和偽標頭順序,任何具備指紋感知能力的伺服器都能將其與真實瀏覽器區分開來。將兩種指紋疊加,比單獨使用任一種都更難繞過。
這與機器人偵測技術指南中描述的複合層原則相同:可觀察協定層之間的不一致,比任何單一異常都更有力地證明存在欺騙行為。
HTTP 標頭順序:一個相關訊號
除了二進位分幀訊號之外,HEADERS 幀中普通 HTTP 標頭的順序也攜帶資訊。Chrome、Firefox 和 Safari 各自按照由瀏覽器請求準備邏輯決定的固定順序發出標頭——Accept、Accept-Language、Accept-Encoding、User-Agent、Upgrade-Insecure-Requests——而非由頁面或使用者決定。自動化函式庫則按不同的預設順序發出標頭,通常是按字母順序或按程式碼中新增的順序。
標頭順序與 Python 的 requests 或 Go 的 net/http 相符而非 Chrome 標準順序的請求,很可能不是真實瀏覽器,無論 User-Agent 欄位聲稱什麼。標頭順序指紋在 HTTP/1.1 和 HTTP/2 上都有效,通常與二進位分幀訊號結合使用,獲得更豐富的綜合評分。
實際測試
與 Canvas 或 WebGL 等瀏覽器指紋識別訊號不同——這些訊號可以透過頁面內的 JavaScript 讀取——HTTP/2 指紋識別本質上是伺服器端的。SETTINGS 和 WINDOW_UPDATE 幀是二進位分幀內容,永遠不會到達頁面的 JavaScript 上下文,因此測試需要一個在將連線交給應用層之前讀取和解譯這些原始幀的伺服器。
BrowserLeaks 的 /http2 端點顯示你的即時 Akamai 指紋字串——你的當前客戶端正在傳送的四段值。BrowserInsight 的機器人偵測工具涵蓋互補的客戶端訊號(自動化痕跡、無頭瀏覽器洩漏、指紋一致性)。TLS 層則透過網路診斷頁面單獨呈現。
常見問題
HTTP/3 有類似的指紋嗎?
有,但訊號有所不同。HTTP/3 執行在 QUIC 而非 TCP+TLS 之上,QUIC 攜帶自己的連線參數——嵌入在 QUIC Initial 封包中的傳輸參數——因實作而異。HTTP/3 的 SETTINGS 幀由 QPACK 控制串流承載,提供與 HTTP/2 SETTINGS 類似的訊號。隨著 HTTP/3 越來越普及,主動研究正在將 HTTP/2 式指紋識別擴展到 HTTP/3。
機器人能透過偽造 User-Agent 來規避 HTTP/2 指紋識別嗎?
不能。User-Agent 標頭由應用程式碼在 HEADERS 幀中設定,但 SETTINGS 幀、WINDOW_UPDATE 和 PRIORITY 幀由 HTTP/2 函式庫在任何應用程式碼執行之前發出。偽造 Chrome User-Agent 同時使用 Go 的 net/http 或 Python 的 httpx 的機器人,仍然傳送該函式庫的 SETTINGS 值和偽標頭順序,而非 Chrome 的。
HTTP/2 指紋識別今天在正式環境中使用嗎?
是的。主要 CDN、機器人管理廠商和大型網站將其與 TLS 指紋識別和行為訊號結合使用,作為多層機器人評分的一部分。由於它不需要執行 JavaScript,且在伺服器傳送任何回應之前就捕獲了幀,因此在沒有精確的函式庫層級仿真的情況下特別難以規避。
既然 PRIORITY 對指紋如此有用,為何要廢棄它?
PRIORITY 在 RFC 9113 中被移除,原因與指紋識別完全無關——實作者發現它難以正確支援,且在實務中對延遲幾乎沒有可測量的改善。廢棄減少了現代客戶端指紋的一個維度,但這也意味著任何仍在傳送舊 PRIORITY 模式的客戶端,很可能執行的是較舊的瀏覽器版本,這本身就是一個有用的分類訊號。


