REALITY 與 XTLS Vision 科普:握手與傳輸層為何更快

REALITY 改的是 TLS 握手,讓伺服器不再出示自有憑證;XTLS Vision 改的是握手之後的傳輸,省掉內層 TLS 的重複加密。兩者解決的問題不同,可以單獨使用,也可以疊加在同一個 VLESS 節點上。

本文速覽

本文把 REALITY 與 XTLS Vision 拆成「握手」與「傳輸」兩段來說:REALITY 如何從目標網站取得憑證鏈完成握手、未授權的連線會被轉送到哪裡;XTLS Vision 如何辨識 TLS 記錄並直通轉送、省下的是哪一層加密。讀完之後,可以判斷自己的節點適合哪種組合,以及 CDN 中轉、WebSocket 傳輸、v2fly 核心這些情境為什麼用不上,並能在 v2rayN 與 v2rayNG 裡把 REALITY 欄位與 flow 參數填對。

結論:一個改握手,一個改傳輸

REALITY 是 VLESS 在傳輸安全層的一種實作方式,作用點在握手階段。伺服器不持有自有網域憑證,而是從目標網站(dest)取得憑證鏈用於握手;用戶端不用公開 CA 驗證伺服器,改用設定裡預先設定的公鑰驗證身分。未通過驗證的連線會被整條轉送到 dest,看到的是目標網站的實際頁面與真實憑證鏈。

XTLS Vision 作用在握手之後。代理 HTTPS 流量時,用戶端與目標網站之間本來就有一層 TLS;XTLS 讓用戶端在完成外層握手後,不再把內層 TLS 記錄塞進外層記錄層重複加密,而是直接轉送這些已經加密的記錄,伺服器辨識後同樣直接轉送給目標網站。省掉的是重複的那一層,不是僅有的那一層。

兩者都由 Xray 核心實作,可以單獨使用,也可以組合:VLESS + TCP + REALITY + flow=xtls-rprx-vision 是目前伺服器端常見的寫法。只開 REALITY 不開 flow,握手階段的偽裝效果不變,只是大流量下要多付一次加解密的 CPU 開銷。

1-RTT
TLS 1.3 完整握手
0-RTT
工作階段恢復握手
443
建議監聽連接埠
TCP
兩者的傳輸方式限制

TLS 握手階段:延遲與指紋出在哪裡

TLS 1.3 的完整握手需要 1 次來回,工作階段恢復可以做到 0-RTT。握手封包裡的 SNI、加密套件清單、擴充順序、金鑰共享群組共同構成用戶端指紋;伺服器回傳的憑證鏈、簽章演算法、工作階段票據構成伺服器指紋。任何一項與「一般 HTTPS 網站」不一致,都可能成為被區分的特徵。

傳統自建節點的做法,是用自有網域申請憑證,或是使用自簽憑證。前者的成本是網域與憑證續期,後者則容易出現憑證鏈不完整、SNI 與憑證不相符的情況,在沒有正確回落設定的情況下很容易被辨識出來。

觀察重點自簽憑證 + 回落REALITY
伺服器出示的憑證自簽憑證,瀏覽器提示不受信任目標網站的實際憑證鏈
SNI 與憑證是否相符常見的不相符情況一致
未授權存取 443 連接埠取決於回落設定,可能曝光代理行為轉送到 dest,回傳實際頁面
用戶端身分驗證方式憑證鏈驗證或略過驗證預置公鑰 + X25519 金鑰交換
網域與憑證成本需要網域,憑證需續期不需要自有網域與憑證

表裡的差異集中在握手的前幾個封包。REALITY 的目標是讓這幾個封包與「直接存取該目標網站」無法區分,而不是把流量藏起來——流量本身仍是標準 TLS,記錄格式、版本號、擴充都與一般 HTTPS 一致,只是憑證來源與驗證方式換了一套。

REALITY:借用真實網站的憑證鏈

伺服器端設定 REALITY 需要四個關鍵值:dest(目標網站,例如 www.python.org:443)、serverNames(與 dest 相符的網域清單)、privateKey(伺服器私鑰,用 xray x25519 指令產生)、shortIds(短 ID 清單,用來區分不同用戶端)。用戶端持有對應的 publicKey、serverName 與 shortId,三項與伺服器端一一對應。

收到連線後,伺服器端用私鑰與 ClientHello 裡的臨時公鑰進行 X25519 運算,能得出預期結果就當作代理處理;得不出結果,就把整條連線轉送給 dest,由目標網站正常回應。這也是挑選目標網站的依據:真實存在、支援 TLS 1.3 與 X25519、有正常網頁,最好還支援 HTTP/2,回落時的表現才會自然。

REALITY + VLESS TCP

推薦

不需要自有網域與憑證,單一 443 連接埠同時負責握手偽裝與代理;未授權的存取看到的是目標網站的實際頁面。

適合:直連環境、單機自建、需要抵抗主動探測

網域憑證 + TLS + WebSocket

設定直觀,憑證需要定期續期,傳輸層可以疊加 WebSocket,方便後續接入 CDN 中轉。

適合:已有網域、需要走標準 443 TLS

自簽憑證 + WebSocket + CDN

來源站台 IP 被 CDN 隱藏,但憑證鏈通常不完整,需要仔細設定回落,否則握手特徵依然明顯。

適合:需要隱藏來源站台 IP、可接受較多設定步驟

結論:先確定要不要走 CDN,再選握手方案

REALITY 與 XTLS Vision 都依賴 RAW(TCP)直連,一旦決定用 CDN 中轉,兩者都無法疊加,應該回到「網域憑證 + WebSocket」的組合;確定直連之後,REALITY 就是不用買網域也能取得真實憑證鏈的方案。

限制也要寫清楚:dest 與 serverNames 必須相符,填錯會出現握手能完成、但頁面回報憑證錯誤的情況;shortId 與 publicKey 必須成對派發,用戶端填錯會直接連不上;不能疊加 WebSocket、gRPC、HTTP/2 等傳輸方式,因此走不了 CDN;v2fly 核心(V2flyNG)對 VLESS 的支援完善,但不解析 REALITY 相關欄位,REALITY 節點需要在 Xray 核心上執行,v2rayNG 內建的就是 Xray 核心。

XTLS Vision:握手之後省掉一層加密

代理 HTTPS 時的資料路徑是:用戶端與目標網站之間一層 TLS,用戶端與代理伺服器之間再一層 TLS。外層 TLS 用來保護用戶端到代理伺服器這一段;內層 TLS 記錄在用戶端送出時已經加密過一次,一般實作會把它當成普通位元組流,再套進外層記錄層加密一遍。

XTLS 的做法是在外層握手完成後辨識第一筆應用資料:如果是 TLS ClientHello,代表這條連線上的資料本身已經加密,外層不再重複加密,直接轉送;如果不是 TLS 流量,例如明文 HTTP,仍照一般方式加密傳輸。判斷依據是首包內容,不需要額外開關。

Vision 是 XTLS 的改良實作,解決了早期 xtls-rprx-direct 在部分情境下的相容性問題,並加入 UUID 驗證與首包辨識。它在設定裡以 flow 欄位的形式出現:伺服器端 clients 寫 "flow": "xtls-rprx-vision",用戶端 outbound 填同一個值,兩端不一致時連線會失敗,或退回一般 VLESS。

設定重點:金鑰、flow 與回落驗證

  1. 產生金鑰對

    伺服器端執行 xray x25519,取得私鑰與公鑰;私鑰只留在伺服器端設定裡,公鑰隨節點資訊派發給用戶端。

  2. 填寫入站設定

    inbound 用 VLESS + TCP 監聽 443,streamSettings.security 設為 reality,填入 dest、serverNames、shortIds 與 privateKey。

  3. 用戶端填公鑰

    在 v2rayN 的節點編輯裡填入位址、連接埠 443、UUID,flow 選 xtls-rprx-vision,再填 publicKey、serverName、shortId。

  4. 驗證回落行為

    用瀏覽器直接存取該網域與連接埠,應該會看到 dest 網站的頁面;若出現憑證錯誤,代表 dest 與 serverNames 不相符。

  5. 查看核心日誌

    連線失敗時,查看日誌裡 REALITY、invalid user、flow 相關的關鍵字,先確認公鑰與 shortId 是否成對派發。

{
  "port": 443,
  "protocol": "vless",
  "settings": {
    "clients": [
      { "id": "8f7a2c1e-5b3d-4a9f-9c21-7d6e4b0a1f33", "flow": "xtls-rprx-vision" }
    ],
    "decryption": "none"
  },
  "streamSettings": {
    "network": "tcp",
    "security": "reality",
    "realitySettings": {
      "dest": "www.python.org:443",
      "serverNames": ["www.python.org"],
      "privateKey": "aP3nQ8vK2sL7dF9xR4tY6uW1zC5bN0mJ2hG8kD3sQ1E",
      "shortIds": ["6ba85179e30d4fc2"]
    }
  }
}

範例片段裡 dest 與 serverNames 指向同一個網域,這是 REALITY 能正常握手的前提;shortIds 可以列出多筆,每個用戶端用一個,更換用戶端時不必重新產生伺服器端金鑰。用戶端這邊的 publicKey 是上面私鑰的配對公鑰,不是另一個隨機值,填錯會直接連不上。

常見問題:探測、相容性與核心差異

別人直接存取我的 443 連接埠會看到什麼?

沒有攜帶正確公鑰的連線會被轉送到 dest 網站,看到的是該網站的實際頁面與憑證鏈;前提是 serverNames 與 dest 相符、回落鏈路沒有被改壞。

REALITY 節點能套 CDN 嗎?

不行。REALITY 與 XTLS Vision 都依賴 RAW(TCP)直連,WebSocket、gRPC、HTTP/2 這些能由 CDN 承載的傳輸方式無法疊加,需要換回「網域憑證 + WebSocket」的組合。

用戶端填了 flow 卻連不上?

先確認伺服器端 clients 裡也寫了同一個 flow,再確認用戶端用的是 Xray 核心;v2fly 核心不解析 REALITY 欄位,節點參數裡填了也不會生效。

只開 REALITY 不開 Vision 行不行?

可以。REALITY 解決握手偽裝,Vision 解決傳輸層重複加密,兩者相互獨立;不開 flow 時握手效果不變,只是大流量下 CPU 佔用會高一些。

dest 一定要選大站嗎?

選支援 TLS 1.3 與 X25519、有正常網頁、且與自己節點不同網域的網站即可;dest 與 serverNames 必須相符,不要填自己的網域,也不要用只回傳 API 資料的網域。

情境組合:直連、CDN 與核心選擇

單機自建、有獨立 IP、不需要隱藏來源站台:VLESS + TCP + REALITY + xtls-rprx-vision。一個 443 連接埠同時負責握手偽裝與傳輸最佳化,不需要網域與憑證,設定項目最少,用戶端用 v2rayN 或 v2rayNG 都可以。

已有網域與憑證、需要走 CDN:VLESS + WebSocket + TLS。這時候 REALITY 與 Vision 都用不上,最佳化方向在 CDN 端與傳輸方式的選擇,而不是握手與傳輸層。兩條路線的分歧點在「來源站台 IP 要不要曝光」,先回答這個問題,後面的參數才有意義。

結論:先定傳輸方式,再定握手方案

有 CDN 需求時,REALITY 與 Vision 都不在可選範圍內;確定直連後,再依「要不要維護自有網域」二選一:不想維護就用 REALITY,已有網域且習慣標準 TLS 就用網域憑證。兩種方案的握手來回都是 1-RTT,差距不在延遲,而在憑證來源與探測特徵。

下載 v2rayN