題幹與適用場景
一個支付合作方要求驗證每個 HTTP 請求的傳送方和內容完整性。請基於 RFC 9421 設計簽名與驗簽流程,並說明覆蓋哪些元件、如何防重放、輪換金鑰以及處理代理改寫。
RFC 9421 將簽名輸入、覆蓋的 HTTP 元件和 created、expires、nonce 等參數分開定義。題目考察能否把「誰簽的」和「哪些位元組被簽」落實為可互通協定,而不是只說「給 body 做 SHA-256」。
面試官考察點
重點包括:覆蓋元件是否足以綁定請求語意;客戶端和伺服器如何規範化簽名基線;時間、nonce 和金鑰 ID 如何防重放;代理、重試、壓縮和多租戶如何影響驗簽;以及金鑰發布、撤銷和監控是否可維運。
30 秒回答框架
「我先定義協定要求覆蓋的方法、目標路徑、authority、關鍵業務標頭和 Content-Digest,並固定簽名演算法、參數順序和時鐘容差。伺服器先解析 Signature-Input,按相同規則重建簽名基線,再查金鑰、驗證簽名、檢查 created、expires 和一次性 nonce,最後才進入業務。金鑰用版本化 key ID 支援雙寫驗簽和撤銷;代理只能改寫未覆蓋欄位,否則驗簽失敗。」
分步驟深入解答
第一步:明確要證明的屬性
簽名可證明持鑰方對特定 HTTP 元件簽過名,也能偵測傳輸中的改寫;它不取代 TLS、授權、輸入校驗或業務冪等。先寫清楚需要認證、完整性,還是不可否認性。
第二步:選擇覆蓋元件
至少覆蓋方法、目標路徑和 authority;依業務再覆蓋 content-digest、冪等鍵、租戶 ID 或關鍵業務標頭。不要只簽一個可被替換的欄位,也不要盲目覆蓋會被合法代理重寫的標頭。元件清單必須成為版本化協定。
第三步:規範化簽名基線
客戶端和伺服器必須使用 RFC 9421 規定的元件識別、順序、參數編碼和衍生元件規則。伺服器不能直接拼接原始 Header 字串猜測結果;應從解析後的請求和 Signature-Input 重建同一基線,並拒絕未知或重複的關鍵元件。
第四步:保護請求內容
有 body 的請求先產生 Content-Digest,再把該欄位納入簽名。驗簽前按收到的位元組計算摘要,確保壓縮、轉碼或 JSON 重排不會靜默改變內容。若代理會解壓或重編碼,協定必須明確簽名發生在修改前還是修改後。
第五步:設計時間與防重放
要求 created,必要時要求 expires 和唯一 nonce。伺服器校驗時間窗口和時鐘偏差,並在租戶範圍短期記錄已用 nonce;重試相同業務請求依賴冪等鍵,不是無限放寬簽名有效期。時間通過不代表業務請求可以重複執行。
第六步:實作金鑰發現與輪換
Signature-Input 帶有 key ID,伺服器從受控目錄或類 JWKS 發布端點讀取公鑰,並快取帶版本的結果。輪換時先發布新公鑰,再允許新舊 key 雙驗簽,確認舊流量耗盡後撤銷舊 key。私鑰只在簽名端使用,日誌不得記錄金鑰材料或完整簽名基線。
第七步:處理代理與重試邊界
明確哪些層可以新增追蹤標頭、重試請求或改變 authority。被覆蓋元件發生不被協定允許的改寫就應驗簽失敗;代理重試不能複製一次性 nonce,也不能把簽名轉發到不同目標。伺服器驗簽前不要執行寫入或昂貴業務邏輯。
第八步:觀測和故障處理
記錄 key ID、簽名版本、失敗類別、時鐘偏差、nonce 衝突、元件缺失和代理來源,使用請求 ID 關聯日誌。對合作方提供可操作錯誤碼,例如過期、未知 key、摘要不匹配;不要返回可幫助攻擊者試錯的詳細金鑰或基線內容。
設計取捨與邊界
非對稱簽名還是共享金鑰
非對稱金鑰便於多方驗簽和獨立撤銷,代價是簽名與金鑰基礎設施更複雜。共享 HMAC 成本較低,但驗證方也能偽造請求,適合雙方完全互信且邊界清晰的場景。
覆蓋範圍還是代理相容
覆蓋越多,完整性約束越強;覆蓋會被閘道合法修改的欄位則會造成誤失敗。把代理契約寫入協定,必要時由邊界代理重新簽名,而不是靜默放寬驗簽。
嚴格時間窗口還是離線重試
短窗口降低重放風險,卻要求時鐘同步和快速重試。離線客戶端應申請新的簽名,不應重用長期有效簽名;伺服器可按合作方設定受控容差。
失敗演練與演進計畫
代理修改路徑
在測試代理中改寫路徑或 authority,確認驗簽失敗且沒有進入業務;允許的追蹤標頭改寫不應影響簽名。
重放舊請求
重複傳送相同簽名和 nonce,驗證第二次被拒絕;使用新 nonce 但相同冪等鍵時,驗證業務層按冪等規則處理。
金鑰輪換窗口
同時發布新舊 key,驗證新舊簽名均能按策略通過;撤銷舊 key 後舊簽名應失敗,且不會因快取無限存活。
常見誤區與追問
誤區一:只簽 body 的雜湊
追問:攻擊者能否把簽名複製到另一個路徑或方法?應覆蓋目標元件並綁定請求語意。
誤區二:認為 HTTPS 已經足夠
追問:終止 TLS 的代理之後如何證明原始傳送方和內容沒有被內部層改寫?
誤區三:忽略 nonce 和時間
追問:捕獲的合法簽名能否在有效期內重複扣款?應結合時間窗口、nonce 和冪等鍵。
誤區四:輪換時立即刪除舊 key
追問:在途請求和多區域快取如何過渡?應先雙驗簽,再撤銷舊 key。
誤區五:把驗簽錯誤直接返回基線細節
追問:如何讓合作方排障又不洩露簽名輸入、金鑰或內部代理資訊?
延伸追問與參考答案
Content-Digest 為什麼還要放進簽名?
摘要證明 body 位元組,簽名把摘要與方法、目標和其他元件綁定,避免攻擊者把合法摘要搬到另一請求。
代理改寫後應該重新簽名嗎?
若改寫欄位屬於下游協定的一部分,邊界代理應以自己的身份重新簽名;否則應保持被覆蓋元件不變並讓原簽名繼續驗證。
如何區分認證和授權?
驗簽確認持鑰方簽過請求,授權仍需檢查租戶、帳戶、金額、冪等鍵和業務狀態,不能由簽名單獨決定是否執行。