通用面試:如何設計 Oblivious HTTP 的 Relay 與 Gateway?
題干與適用場景
一個遙測客戶端希望讓目標服務無法把請求關聯到客戶端身份,同時又不讓轉發節點看到請求內容。請設計 OHTTP 的客戶端、Relay、Gateway 和 Target,涵蓋金鑰發現、HPKE 封裝、錯誤處理、重放防護、資源映射、限流和監控。
RFC 9458 將 OHTTP 定義為轉發加密 HTTP 訊息的標準:Relay 看到客戶端連線,Gateway 能解密並訪問 Target,但二者不應單獨同時取得客戶端身份與請求內容。它不是匿名網路;訊息長度、時序、Relay/Gateway 串通、客戶端中繼資料和應用層標識仍需單獨處理。
面試官考察點
- 能否明確 Client、Relay、Gateway、Target 的可見資料和信任邊界。
- 是否理解 Gateway 公鑰、HPKE 封裝請求/回應和媒體類型。
- 能否設計 replay 防護、請求大小限制、逾時和錯誤映射。
- 是否考慮 Relay 與 Gateway 的一對一資源映射、流量分析和串通風險。
- 能否處理金鑰輪換、快取、失敗重試和客戶端時鐘偏差。
- 能否用接受率、解密失敗、重放拒絕、延遲和長度分布驗證系統。
回答前需要釐清的問題
- 目標是單向遙測、公開讀取,還是包含高價值寫操作?敏感寫操作需要更強的認證和防重放。
- Relay 與 Gateway 是否由不同營運方控制,是否允許同一組織擁有兩者?
- Target 是否需要按使用者授權、租戶或地域返回不同結果?
- 請求大小、批量窗口、最大延遲和丟失容忍度是多少?
- 是否允許客戶端在金鑰過期時重新發現配置,日誌中哪些欄位必須脫敏?
30 秒回答框架
我會先畫出四方邊界:客戶端向 Relay 建立連線,Relay 只轉發封裝訊息,Gateway 用公開金鑰解密並呼叫 Target。客戶端從 Gateway 取得 key configuration,用 HPKE 封裝二進位 HTTP 請求;回應沿相反路徑封裝返回。Gateway 用時間窗口、唯一請求識別或應用層冪等防重放,Relay 限制連線與訊息資源。金鑰輪換保留重疊期,監控解密失敗、重放拒絕、延遲和長度分布;不把 OHTTP 當成能抵抗串通或流量分析的匿名系統。
分步驟深入解答
1. 先定義四方職責
Client 知道目標資源和 Gateway 公鑰;Relay 知道客戶端網路連線但不應讀取封裝內容;Gateway 解密請求並向 Target 發起普通 HTTP;Target 只看到 Gateway 的來源。Relay 和 Gateway 的部署、日誌與存取權限應分離,否則單點可能同時關聯身份與內容。
2. 發現並驗證金鑰配置
客戶端取得 Gateway 的 key configuration,包含 key identifier、HPKE 演算法和公鑰。配置需要版本、有效期和來源認證;客戶端拒絕不支援的演算法或過期金鑰。輪換時同時發布舊、新金鑰,等待客戶端快取與請求窗口結束後再撤銷舊私鑰。
3. 封裝請求和回應
客戶端把二進位 HTTP 請求編碼後用 HPKE 封裝,發送 message/ohttp-req 負載;Gateway 解封裝後校驗方法、目標資源、大小和內容類型。回應再以 message/ohttp-res 封裝給客戶端。Relay 不應解析內層 HTTP,也不應根據明文狀態碼做差異化路由。
Client -- TLS --> Relay -- opaque OHTTP --> Gateway -- HTTP --> Target
Client <-- opaque response -- Relay <-- OHTTP response -- Gateway4. 處理認證、重放和冪等
OHTTP 隱藏客戶端網路身份,不能自動提供業務使用者認證。對寫請求使用應用層簽名、一次性 nonce、時間窗口或冪等鍵;Gateway 維護最小的重放檢測狀態,並限制同一封裝訊息重複提交。對遙測批次可採用冪等事件 ID,避免重試產生重複計數。
5. 處理錯誤和資源映射
Gateway 無法解密時返回結構化的 key 或封裝錯誤,不能把內部金鑰細節寫入回應。Target 的業務錯誤要透過 OHTTP 回應安全傳回。Relay 與 Gateway 的資源映射應固定且可驗證,避免 Relay 把封裝訊息轉發到錯誤目標。逾時、大小超限和過載應在各層分別限流。
6. 評估隱私洩露和流量分析
即使內容加密,Relay 仍能觀察連線時序、訊息長度和客戶端 IP;Gateway 仍能觀察請求頻率、解密後的應用欄位和 Target。使用批量窗口、填充、速率限制和分離日誌降低關聯風險,但會增加延遲和成本。不要承諾 OHTTP 防止 Relay/Gateway 串通。
7. 灰度、監控和回退
先讓一小組客戶端使用獨立 Relay/Gateway 資源,記錄配置命中、解密成功率、重放拒絕、Target 5xx、p95 延遲、訊息大小分布和回退率。故障時只對目標資源或客戶端版本停用 OHTTP,普通 HTTPS 回退必須經過隱私評審;日誌保存配置 ID、錯誤類別和請求雜湊,不記錄內層身份欄位。
高品質示範回答
我會把客戶端、Relay、Gateway 和 Target 分成四個責任域。客戶端取得並驗證 Gateway 的 HPKE key configuration,把二進位 HTTP 請求封裝後發給 Relay;Relay 只轉發不透明訊息;Gateway 解封裝、檢查大小與資源映射,再以自己的身份請求 Target,回應沿相反方向封裝。
OHTTP 不提供業務認證,也不抵抗 Relay 與 Gateway 串通。因此寫請求要加應用層簽名、nonce 或冪等鍵,Gateway 用時間窗口做重放拒絕。金鑰輪換保留新舊重疊期,Relay 限制連線和訊息資源。灰度看解密失敗、重放拒絕、延遲、長度分布和業務錯誤;只在明確評估後才允許普通 HTTPS 回退。
常見錯誤
- 把 Relay 當作能解密請求的代理 → 失去隱私邊界 → Relay 只處理外層連線和不透明訊息。
- 認為 OHTTP 自動完成使用者認證 → Target 無法識別合法業務主體 → 使用應用層簽名或授權令牌。
- 忽略訊息長度和時序 → 流量分析仍可關聯 → 採用填充、批量窗口並衡量延遲成本。
- 重試寫請求卻沒有冪等鍵 → 遙測重複計數或副作用重複 → 設計 nonce、事件 ID 和重放窗口。
- Relay 與 Gateway 共用可關聯日誌 → 單點即可還原身份與內容 → 分離營運、日誌欄位和存取權限。
追問及應對
OHTTP 能否防止 Relay 與 Gateway 串通?
不能。協議依賴有限信任和營運分離;串通方可能把連線身份與解密內容重新關聯。需要組織、日誌和存取控制層面的獨立性。
Gateway 如何防重放?
對寫請求使用時間窗口、nonce、冪等事件 ID 或應用簽名;保存最小檢測狀態並拒絕重複封裝訊息。只依賴 TLS 連線不能防止跨連線重放。
為什麼需要資源映射?
一個 Relay 應把封裝請求轉發到指定 Gateway/Target 資源。固定映射讓金鑰、策略、限流和審計邊界可驗證,也避免把訊息誤發到不相容的 Gateway。
如何輪換 Gateway 公鑰?
發布帶版本和有效期的新 key configuration,保留舊金鑰的重疊窗口,按 key ID 觀察命中與解密失敗,等快取、批量和重試窗口結束後再撤銷舊私鑰。
OHTTP 適合高價值寫操作嗎?
需要謹慎。它隱藏網路身份但不替代認證、授權、冪等和審計;高價值寫操作應先證明應用層主體和重放邊界,再決定是否接受額外延遲與隱私收益。
監控應該記錄什麼?
記錄配置 ID、Relay/Gateway 資源、錯誤類別、請求大小桶、重放拒絕和端到端延遲;預設不記錄內層網域、使用者標識或原始封裝內容。