跳到內容

OAuth 2.0 Security Best Current Practice

RFC 9700 是 OAuth 2.0 的安全最佳實踐指南,於 2025 年 1 月正式發布。它的前身是 2013 年的 RFC 6819,但 RFC 9700 大幅更新了威脅模型,並將過去十年在實作與部署中發現的安全問題系統化整理成規範。

RFC 9700 本身不定義新的協定機制,而是明確哪些做法是必須的(MUST)、哪些是建議的(SHOULD),以及哪些已不應再使用(MUST NOT)。

RFC 9700 在 §3 定義了五種攻擊者類型,作為所有安全建議的共同基礎:

類型能力描述
A1 網路攻擊者可架設任意伺服器、誘導使用者造訪惡意連結
A2 中間人攻擊者除 A1 外,還可竊聽與竄改未加密的網路流量
A3 授權回應讀取者可讀取(但不能修改)授權回應的內容
A4 授權請求讀取者可讀取(但不能修改)授權請求的內容
A5 Token 取得者可透過各種手段取得已核發的 Access Token

各類型攻擊者的詳細能力邊界、典型攻擊場景與對應防護,請參考攻擊者模型

Authorization Server 在比對 redirect URI 時,必須使用完全字串比對(exact string matching),不得使用前綴比對、萬用字元或正規表達式。唯一的例外是 localhost 的埠號可以不比對,以方便原生應用開發。

不嚴謹的 redirect URI 驗證是 OAuth 攻擊中最常見的漏洞來源之一,攻擊者可藉此將授權碼或 Token 導向惡意端點。

此外,Authorization Server 與 Client 不得提供任何開放式重新導向(open redirector)端點。

§2.1.1 明確要求:

  • Public Client 必須使用 PKCE,以防止授權碼注入攻擊
  • Confidential Client 建議使用 PKCE,OpenID Connect 的 nonce 參數亦可作為替代方案
  • Authorization Server 必須支援 PKCE,且必須防止 PKCE downgrade 攻擊(即攻擊者移除 code_challenge 參數以繞過保護)

PKCE 的 challenge 值必須針對每次授權流程單獨產生,不可重複使用。

§2.3 建議對 Access Token 的使用範圍加以限制:

  • Access Token 應限定給特定的 Resource Server(audience restriction)
  • Access Token 應進一步限定可執行的資源與操作
  • 遵循最小權限原則,只授予本次請求所需的最低 scope

這些措施可以降低 Token 洩漏或被盜用後的損害範圍。

§2.2 建議將 Token 綁定到特定的 Client,使竊取的 Token 無法被其他人使用:

  • Access Token:建議使用 sender-constraining 機制(如 DPoPMutual TLS
  • Refresh Token:Public Client 的 Refresh Token 必須使用 sender-constraining 或 refresh token rotation 其中一種機制

§2.5 建議:

  • Authorization Server 應在可行的情況下強制 Client 進行認證
  • 建議使用非對稱加密(asymmetric cryptography)進行 Client 認證,例如 private key JWT,而非共享的 client secret

Client secret 容易在原始碼、日誌或設定檔中洩漏;非對稱金鑰只需保管私鑰,安全性更高。

Refresh Token 的有效期較長,一旦洩漏影響範圍更大。除了前述的 sender-constraining 外,§2.2.2 建議:

  • 對 Public Client 使用 Refresh Token rotation:每次使用 Refresh Token 換發新 Token 時,同時核發新的 Refresh Token 並作廢舊的
  • 若偵測到同一個 Refresh Token 被使用超過一次,應視為可能的 Token 竊取,立即撤銷所有相關 Token

§2.6 要求所有 OAuth 端點都必須使用 TLS:

  • Authorization Server 的所有端點(Authorization Endpoint、Token Endpoint、Introspection Endpoint 等)必須使用 TLS
  • Client 與 Resource Server 之間的通訊必須使用 TLS
  • 唯一的例外是原生應用的 localhost redirect URI,可以不使用 TLS(因為流量不經過網路)

此外,建議 Authorization Server 採用 Authorization Server Metadata(RFC 8414) 來公開端點資訊,讓 Client 自動取得正確的端點 URL,減少手動設定錯誤的風險。

Mix-Up 攻擊(§4.4)發生在 Client 同時支援多個 Authorization Server 的情境:攻擊者可以操控 Client,讓它誤以為回應來自可信的 AS,實際上卻把授權碼或 Token 傳送給攻擊者控制的惡意 AS。

sequenceDiagram
    actor User
    participant Client
    participant A_AS as 攻擊者 AS(A-AS)
    participant H_AS as 合法 AS(H-AS)

    User->>Client: 1. 選擇 A-AS 登入
    Client->>A_AS: 2. 授權請求<br/>(Session 記錄:目標 AS = A-AS)
    Note over A_AS: 攻擊者攔截,替換 client_id
    A_AS-->>User: 3. 重新導向到 H-AS
    User->>H_AS: 4. 使用者在 H-AS 登入並授權
    H_AS-->>User: 5. 回傳授權碼(H-AS 核發)
    User->>Client: 6. Callback 帶回授權碼
    Note over Client: Session 顯示目標 AS = A-AS
    Client->>A_AS: 7. 拿授權碼換 Token<br/>(誤送到 A-AS 的 Token Endpoint)
    Note over A_AS: 攻擊者取得 H-AS 核發的授權碼

防護措施:

  • Authorization Server 在授權回應中附帶 iss 參數(RFC 9207),Client 必須驗證 iss 與當初發起請求的 AS 相符
  • 或是為每個 Authorization Server 設定不同的 redirect URI,讓 Client 可以從 callback URL 確認回應來源

§4.7 說明 CSRF 攻擊在 OAuth 中的具體形式:攻擊者可以偽造一個授權回應,把自己的授權碼注入受害者的 session,讓受害者的 Client 綁定到攻擊者的帳號。

防護措施(擇一即可):

  • state 參數:Client 在授權請求中附帶隨機值,callback 時驗證 state 與 session 中儲存的值一致
  • PKCEcode_verifier 與授權請求綁定,本質上也能防止 CSRF
  • nonce(OpenID Connect):與 PKCE 提供等效的保護

§4.12 提醒一個容易忽略的實作細節:

Authorization Server 如果在處理使用者憑證的過程中需要重新導向,必須使用 303 而非 307。HTTP 307 會保留原始請求的方法與 body,若 Authorization Server 在收到 POST 請求(含帳號密碼)後以 307 重新導向,瀏覽器會把含有密碼的 POST body 一併送往導向目標,造成憑證外洩。

§4.16 說明攻擊者可以用透明的 iframe 覆蓋在 Authorization Server 的授權頁面上,誘騙使用者在不知情的情況下點擊「授權」按鈕。

防護措施:

  • Authorization Server 的授權頁面必須設定 X-Frame-Options: DENYContent-Security-Policy: frame-ancestors 'none',防止被嵌入 iframe

§2.1.2§2.4 明確指出兩種流程不應再使用:

  • Implicit Grantresponse_type=token):Access Token 直接暴露於瀏覽器的 URL fragment,容易被竊取,應改用 PKCE
  • Resource Owner Password Credentials(ROPC):要求使用者直接將帳號密碼交給 Client,根本上違反 OAuth 的委派授權設計,禁止使用