後端面試:如何結合 OAuth RAR 與 DPoP 保護交易授權?
題干與適用場景
一個行動銀行客戶端呼叫支付 API,使用者核准向指定收款人轉帳 500 美元。授權伺服器要在同意頁面展示交易細節,複製出的存取權杖不能被另一個客戶端執行個體直接使用。請設計 OAuth 2.0 Rich Authorization Requests(RAR)與 Demonstrating Proof of Possession(DPoP)的組合方案,涵蓋權杖簽發、資源伺服器驗證、重播、金鑰遺失、帳本狀態和驗證。
這是後端安全與 API 契約題。金額、幣別和收款人是面試假設,不是市場事實。
面試官考察點
- 是否能區分使用者同意的交易和存取權杖可呼叫的粗粒度權限。
- 是否知道 RAR 用結構化授權詳細資料表達動作,DPoP 用金鑰綁定權杖並為每次請求證明持有金鑰。
- 是否說得清楚授權伺服器、權杖端點、資源伺服器和支付帳本各自負責什麼。
- 是否涵蓋重播、重複提交、裝置遺失、金鑰洩露和支付方逾時。
- 是否用業務不變量和灰度指標驗證方案,而不是只檢查 JWT 格式。
弱回答會說「把金額放進 scope,再簽一個 JWT」。強回答會保留結構化交易欄位、綁定客戶端金鑰,並讓最終帳本狀態機決定是否扣款。
回答前需要釐清的問題
- 授權伺服器是否擁有支付帳本?若沒有,帳本必須在提交時再次檢查授權決定。
- 一次授權只允許一筆轉帳,還是允許有限次數?這會改變授權詳細資料和權杖壽命。
- 客戶端能否用硬體保護金鑰跨重裝保存?遺失裝置如何撤銷?
- 資源伺服器是否會要求 DPoP nonce?允許多大的時鐘偏差?
- 支付方逾時後是否能查詢狀態?否則必須保留未知狀態,不能直接重試。
30 秒回答框架
「我會用 authorization_details 表達精確轉帳,而不是發明一個包含金額的 scope。客戶端先建立金鑰對,要求權杖時傳送 DPoP proof,授權伺服器把權杖綁定到公鑰。資源伺服器驗證存取權杖、DPoP proof、方法、URI、時間、nonce 和金鑰綁定,再把授權記錄 ID 交給支付帳本。帳本用冪等鍵只允許一次終態轉換。重播、裝置撤銷、支付方逾時和稽核證據分別由各自邊界負責,並用測試證明業務不變量。」
分步深入解答
1. 建模被要求的動作
RAR 定義結構化的 authorization_details 要求。物件應包含已註冊的 type、動作、金額、幣別、收款人識別碼和交易要求號。授權伺服器先驗證 schema、帳戶歸屬、限額和策略,再展示同意頁面。展示的正規化值必須與帳本最後使用的值相同,不能只展示客戶端傳來的名稱。
{
"type": "payment",
"actions": ["transfer"],
"amount": "500.00",
"currency": "USD",
"beneficiary_id": "b_123",
"request_id": "rq_7f2"
}授權結果應引用伺服器擁有的授權記錄。資源伺服器不能從不可信的展示文字重新推導金額、幣別或收款人。
2. 把權杖綁定到客戶端金鑰
客戶端把私鑰保存在受保護儲存中,並向權杖端點傳送 DPoP proof JWT。proof 包含 HTTP 方法、目標 URI、簽發時間、唯一 proof ID 和公鑰。授權伺服器驗證 proof,簽發帶有金鑰確認資訊的權杖。攻擊者即使複製存取權杖,沒有私鑰也無法完成受保護要求。
DPoP 是應用層的持有者約束,不能取代 TLS、安全金鑰儲存、授權策略或裝置撤銷。金鑰證明的是客戶端執行個體持有某把鑰匙,不等於證明使用者核准了某一筆付款。
3. 驗證每一次資源要求
客戶端同時傳送存取權杖和新的 DPoP proof。資源伺服器檢查簽章、權杖過期、issuer、audience、確認指紋、方法、URI、時鐘視窗、必要的 nonce 和 proof ID 重播快取。重用到另一個 URI 或超過視窗的 proof 必須拒絕。存取權杖綁定和授權詳細資料查詢要一起驗證;另一枚權杖的有效 proof 不能代替本次檢查。
4. 讓帳本成為最終權威
資源伺服器產生支付命令,帶上授權記錄 ID、正規化金額和收款人摘要、客戶端執行個體 ID 與冪等鍵。帳本在一個交易中比較命令與核准記錄,只接受尚未使用的授權,寫入 PENDING 或 COMMITTED,拒絕金額或收款人改變、授權過期和第二次終態轉換。外部支付方逾時時寫入 UNKNOWN,透過查詢或對帳確認後再處理;逾時不等於沒有扣款。
5. 處理復原與撤銷
依受保護時間視窗保存 proof ID,並按客戶端與 issuer 限制快取。裝置遺失時撤銷金鑰綁定或授權記錄,而不只是清理瀏覽器工作階段。稽核事件記錄同意內容摘要、展示值、權杖金鑰指紋、資源判定、帳本轉換和人工操作;私鑰與原始權杖不得寫入日誌。新授權詳細資料類型應能單獨關閉,保留舊流程作為回退。
6. 比較替代方案
粗粒度 payments.write scope 簡單,但無法表達一筆金額和一個收款人;帳本仍需另一個可信交易授權。mTLS 也能把權杖綁定到憑證,適合受控伺服器客戶端,但行動裝置憑證生命週期和網路終止更複雜。DPoP 適合應用管理金鑰的 HTTP 客戶端,代價是必須實作 nonce、時鐘、重播快取和金鑰遺失處理。
高品質示範回答
「我會拆成四個決定。第一,RAR 攜帶包含金額、幣別、收款人和伺服器要求號的型別化支付授權,同意頁面顯示正規化值,授權伺服器驗證限額。第二,行動客戶端使用受保護金鑰和 DPoP proof,權杖綁定該金鑰。第三,資源伺服器驗證權杖、proof、URI、時間、nonce 和 proof 重播,再讀取伺服器授權記錄。最後,支付帳本在交易中比較授權記錄和命令,只允許一次冪等終態轉換。沒有私鑰的複製權杖、改變的收款人、重複 proof 和第二次提交都會被拒絕。支付方逾時進入 UNKNOWN 並對帳,絕不盲目重試。我會監控重播拒絕、nonce 失敗、授權不匹配、重複命令、未知結果和撤銷傳播,並用開關灰度新 RAR 類型。」
常見錯誤
- 把金額和收款人放進 scope → scope 變成無邊界字串,失去型別驗證 → 使用註冊的授權詳細資料 schema 和伺服器記錄。
- 把 DPoP 當成人類同意 → 持有金鑰不代表使用者核准了什麼 → 分離同意、權杖綁定和帳本授權。
- 只在閘道驗證 DPoP → 內部呼叫或另一條路由可能繞過 → 在每個資源邊界驗證,並傳遞可驗證的授權記錄。
- 支付方逾時就建立新付款 → 第一次要求可能已成功 → 查詢狀態、使用冪等鍵、保留
UNKNOWN。 - 永久保存 proof ID → 快取無限增長且策略難以解釋 → 依 proof 壽命和時鐘策略設定有界重播視窗。
追問及應對
如果攻擊者同時竊取存取權杖和 DPoP proof 呢?
拒絕重用 proof ID,並執行方法、URI、時間和 nonce 約束。proof 壽命要短,每次要求重新產生。如果私鑰也洩露,撤銷金鑰綁定和授權記錄;DPoP 本身無法修復已洩露的金鑰。
為什麼不把付款寫入 JWT scope?
scope 適合粗粒度權限,付款卻需要型別欄位、展示、驗證和穩定伺服器記錄。可以保留 scope 作為大能力邊界,再由 RAR 和帳本執行精確交易約束。
資源伺服器和授權伺服器意見不一致怎麼辦?
使用伺服器擁有的授權 ID 和版本。高風險動作在記錄不可用或版本過舊時應失敗關閉。帳本在交易中再次檢查版本,舊快取不能提交修改後的付款。
DPoP 能阻止所有重播嗎?
不能。它在攻擊者沒有私鑰時降低複製權杖的重播風險,並幫助伺服器識別重複 proof。持有金鑰的惡意客戶端仍可能重複提交已獲准命令,所以帳本冪等、一次性授權、限流和裝置撤銷仍然必要。