了解 TCP/IP 指紋的運作原理:TTL、視窗大小、MSS 與 TCP 選項順序如何從握手中洩漏你的作業系統,以及 p0f 和 JA4T 如何讀取它們。
在你的瀏覽器送出 TLS ClientHello 的第一個位元組之前,你的作業系統其實早已自我介紹完畢。開啟每一個連線的 TCP 三向握手,會攜帶少數幾個低階參數——初始 TTL、宣告的視窗大小、最大區段大小,以及 TCP 選項的排列順序——這些值都由你的作業系統核心以自身的預設值填入。其中沒有任何一個值是由你或你的應用程式所選擇的,而這組合合在一起的一致性,足以推測出你正在執行哪一種作業系統。這就是 TCP/IP 指紋識別:在協商任何加密之前,就從原始封包標頭被動偵測作業系統。
核心重點
- 指紋是由作業系統核心寫入的,而非瀏覽器。 SYN 封包中的初始 TTL、TCP 視窗大小、MSS 和 TCP 選項排序,都由作業系統的網路堆疊設定——因此指紋識別的是作業系統,而非發出請求的應用程式。
- 它發生在 TLS 之前。 TCP/IP 指紋識別讀取的是三向握手中的 SYN 封包,位於 JA3/JA4 所指紋的 TLS 握手下一層。兩者彼此堆疊在一起。
- 它是被動的。 伺服器只要接受連線就能對你的作業系統取得指紋——無需探測、無需 JavaScript,也不會回傳任何東西給你。p0f 這類工具開創了這種方法;JA4T 則是現代且結構化的版本。
- 它能揭露「作業系統與聲稱不符」的情況。 一個預設值顯示為「Linux」的 SYN 封包,卻搭配聲稱「Windows Chrome」的
User-Agent,這正是機器人偵測中常用的典型偽造訊號。 - NAT、代理和 VPN 會使它變得模糊。 由於這些訊號存在於閘道與通道會改寫的標頭中,指紋反映的是寫入該封包、距離最近的那個堆疊——這也正是它有助於偵測 VPN 與代理的原因。
什麼是 TCP/IP 指紋識別?
每一個 TCP 連線都以三向握手開啟:客戶端送出 SYN,伺服器回覆 SYN-ACK,客戶端再以 ACK 確認。第一個 SYN 封包由作業系統的 TCP/IP 堆疊組裝,而它的幾個欄位並未由協定標準指定數值——標準定義了每個欄位的意義,卻將預設數值交由實作決定。不同的核心會挑選不同的預設值,而且這些值在連線之間鮮少改變。
由於這些預設值內建於作業系統的網路堆疊中,指紋描述的是作業系統及其版本,而非瀏覽器或使用者。同一台 Windows 機器上的兩個不同瀏覽器會產生相同的 TCP/IP 指紋;同一個瀏覽器在 Windows 和 Linux 上則會產生兩個不同的指紋。這與瀏覽器指紋識別恰好相反——後者識別的是應用程式,對底下的核心一無所知。
SYN 封包中的訊號
主要工作由四個標頭值完成,分別取自 IP 層(RFC 791)和 TCP 層(RFC 9293)。
1. 初始 TTL(存活時間,Time To Live)
IP 標頭的 TTL 欄位每經過一個路由器躍點就會減一,因此觀察者永遠不會直接看到原始值——但作業系統都從一小組廣為人知的預設值開始:64(Linux、macOS、現代 BSD)、128(Windows)和 255(部分網路設備與較舊的 Unix)。如果一個封包到達時 TTL 為 57,那它幾乎肯定是從 64 開始並跨越了 7 個躍點。將觀察到的 TTL 向上取整到最接近的常見預設值,就能還原出來源作業系統家族。
2. TCP 視窗大小
TCP 標頭會宣告一個初始接收視窗——也就是傳送方在要求確認之前願意接收多少位元組。確切的起始值因堆疊而異:歷史上 Windows、Linux 和 macOS 各自出貨的初始視窗大小都明顯不同,這個值是 SYN 中最具辨識力的判別依據之一。結合視窗縮放選項(RFC 7323),它能將作業系統範圍縮小,有時甚至能定位到版本。
3. 最大區段大小(MSS)
MSS 選項(RFC 6691)宣告客戶端在單一區段中願意接收的最大 TCP 酬載。它的值衍生自鏈路的 MTU——在標準乙太網路上通常為 1460 位元組(1500 MTU 減去 40 位元組的標頭),但在 PPPoE、通道或 VPN 上會更低。一個不尋常的 MSS 本身就具有資訊量:1400 或更低的值往往洩漏出流量正通過某個通道,這暗示著正在使用 VPN。
4. TCP 選項及其順序
TCP 選項欄位可以攜帶 MSS、視窗縮放、SACK-permitted、時間戳記和 NOP 填補——而關鍵在於,堆疊列出這些選項的順序是因實作而異的。Linux、Windows 和 macOS 各自發出具有特徵的選項排列(例如 MSS, SACK, Timestamp, NOP, Window-Scale 相對於 MSS, NOP, Window-Scale, SACK, Timestamp)。就像 TLS ClientHello 中的延伸順序一樣,排序洩漏的身分資訊比任何單一數值都多。
| 訊號 | 由誰設定 | 典型 Linux | 典型 Windows |
|---|---|---|---|
| 初始 TTL | IP 堆疊 | 64 | 128 |
| 視窗大小 | TCP 堆疊 | 因堆疊而異 | 因堆疊而異 |
| MSS | 由 MTU 衍生 | 1460 | 1460 |
| 選項順序 | TCP 堆疊 | 獨特排列 | 獨特排列 |
被動偵測:p0f 與 JA4T
TCP/IP 指紋識別的決定性特性,在於它是被動的。不同於主動式作業系統偵測工具——它們會送出精心構造的探測封包並測量回應——被動指紋識別器只需觀察客戶端原本就會送出的流量即可。接受一個普通連線就足以讀取 SYN。
p0f 是讓這種方法廣為人知的工具——它是一個被動指紋識別器,將觀察到的 SYN 封包與已知作業系統簽名資料庫進行比對,識別作業系統,有時還能識別運行時間或鏈路類型,全程不向目標送出任何一個封包。它確立了多數被動作業系統偵測至今仍沿用的簽名格式。
JA4T 是 FoxIO 的 JA4+ 套件中位於 TCP 層的成員,與打造現代 JA4 TLS 指紋的是同一個專案。JA4T 將 TCP 視窗大小、依序排列的 TCP 選項、MSS 值和視窗縮放值組合成單一結構化、人類可讀的字串——將 JA4「可排序、可閱讀的指紋」理念帶到傳輸層。由於它位於 TLS 之下,JA4T 甚至能在 ClientHello 被解析之前就標記出一個連線。
它如何與 TLS 指紋識別堆疊運作
TCP/IP 指紋識別與 TLS 指紋識別讀取的是同一段握手序列中相鄰的兩層,而它們識別的東西各不相同:
| 層 | 技術 | 識別內容 |
|---|---|---|
| IP + TCP | p0f / JA4T | 作業系統核心 |
| TLS | JA3 / JA4 | TLS 函式庫(進而是應用程式) |
這種差異正是讓這對組合強大的原因。TCP/IP 指紋說明是哪一種作業系統送出了封包;TLS 指紋說明是哪一種客戶端軟體開啟了工作階段。當兩者不一致時——一個 Windows 風格的 SYN 卻攜帶著符合 macOS Safari 的 TLS 握手——這個連線就在內部自相矛盾,而可觀察層之間的不一致,正是機器人偵測技術背後的核心原則。一個在 Linux 伺服器上執行、偽造 Chrome-on-Windows User-Agent 的爬蟲,仍然會發出 Linux 的 SYN 封包,它所設定的任何標頭都改變不了這一點。
它揭露什麼——以及它的限制
TCP/IP 指紋能揭露作業系統家族與版本,能從 MSS 暗示鏈路類型(乙太網路、PPPoE、通道),並能揭露聲稱平台與實際平台之間的不符。但與較高層的指紋相比,它是個較粗糙的工具,而且有幾項因素會使它變得模糊:
- NAT 與負載平衡器可能改寫或正規化 TCP 選項,因此指紋反映的可能是某個閘道,而非終端主機。
- VPN 與代理會終止或重新封裝連線;伺服器接著對 VPN 端點的作業系統取得指紋,而非你的。這是雙面刃——它隱藏了你真正的作業系統,但一個看似住宅 IP 卻搭配資料中心作業系統指紋的組合,本身就是一個 VPN/代理訊號。
- 解析度低。 TCP/IP 指紋識別能很好地區分作業系統家族,卻無法識別特定的瀏覽器、裝置型號或使用者。它是個粗略的第一道篩選器,而非唯一識別符。
基於這些原因,它幾乎總是被當作眾多輸入之一來使用——與 TLS 和 HTTP/2 指紋、IP 信譽以及行為訊號結合——而非作為單獨的判定依據。
常見問題
我可以改變我的 TCP/IP 指紋嗎?
只能透過改變產生它的作業系統網路堆疊。某些隱私和反審查工具提供「作業系統指紋偽造」,會改寫 TTL、視窗大小和選項順序以模仿另一個系統,但這是在核心/防火牆層級運作的——瀏覽器設定、擴充功能和 User-Agent 覆寫都觸及不到它,因為這些值在任何應用程式碼執行之前就已寫入。
VPN 能隱藏我的 TCP/IP 指紋嗎?
部分能。VPN 會將你的流量封裝在通道中,因此目的地伺服器看到的是 VPN 客戶端堆疊或其出口節點所產生的 SYN 封包,而非你原本的那個。你真正的作業系統指紋被隱藏了,但通道往往會留下自己的痕跡——封裝開銷造成的 MSS 降低,或是與住宅 IP 不相符的作業系統指紋——偵測系統會利用這些痕跡推斷出 VPN 的存在。
TCP/IP 指紋識別和 Nmap 的作業系統偵測是同一回事嗎?
不是。Nmap 執行的是主動作業系統偵測——它送出一系列精心構造的探測封包並分析回應。本文所討論的 TCP/IP 指紋識別則是被動的:它只觀察客戶端在正常連線期間送出的封包,這使它從客戶端的角度看來是無聲且無法察覺的。
為什麼單憑 TTL 無法識別作業系統?
因為 TTL 在每個路由器躍點都會減一,你觀察到的值是起始預設值減去躍點數,而在足夠多的躍點之後,不同的預設值可能會重疊。TTL 能縮小作業系統家族範圍(64 對 128 對 255),但唯有結合視窗大小、MSS 和選項排序——也就是完整簽名,而非任何單一欄位——才可靠。


