PostgreSQL 18 的 OAuth 驗證:如何設計安全的資料庫連線方案?
題目與場景
你的團隊準備把多租戶分析平台升級到 PostgreSQL 18,希望應用使用 OAuth 2.0 bearer token 連線資料庫,減少長期密碼和人工輪替。請說明 PostgreSQL 18 的 OAuth 驗證邊界、連線握手、角色對映與上線遷移方案,並指出最容易造成權限擴大或 issuer 混淆的地方。
面試官考察什麼
- 能否區分 OAuth client、authorization server、resource server 與資料庫角色。
- 能否把
pg_hba.conf、validator、scope、map 和 libpq 參數串成完整資料流。 - 能否識別 discovery、issuer 精確比對、TLS 與 token 生命週期風險。
- 能否設計可回滾的灰度遷移,而不是只說「把密碼換成 token」。
澄清問題
- 連線方是人、後台服務,還是兩者都有?不同主體決定 public 或 confidential client 的選擇。
- 每個租戶是否對應獨立資料庫角色?是否允許一個 token 代表多個角色?
- provider 是否提供標準 discovery 文件和 bearer token validator?
- 舊用戶端能否繼續使用 SCRAM,遷移期間的稽核和回滾視窗多長?
30 秒回答
我會把 PostgreSQL 視為 resource server,把 libpq/psql 視為 OAuth client,把外部身分系統視為 authorization server;資料庫本身不簽發 token。伺服器在 pg_hba.conf 啟用 oauth,設定精確的 issuer、scope 和 validator,必要時用 map 將外部身分對映到資料庫角色。用戶端透過 discovery 取得端點並提交 bearer token,伺服器 validator 驗證簽章、issuer、受眾、到期時間和 scope。上線先保留 SCRAM,按租戶灰度、記錄拒絕原因和角色對映,出現異常時關閉 OAuth 規則即可回滾。
深入拆解
1. 明確信任邊界
PostgreSQL 18 提供 OAuth 驗證方法,但不提供 authorization server。OAuth provider 負責授權和 token 簽發,資料庫負責驗證 token 並決定是否允許連線。把資料庫當作 OIDC 登入頁或讓資料庫直接保存 refresh token,都會擴大責任邊界。
2. 設定伺服器規則
在 pg_hba.conf 為目標網路和資料庫增加 oauth 規則,並設定 issuer、scope、可選 validator 和 map。issuer 必須與 discovery 文件中的 issuer 識別逐字一致;多個 validator 並存時應明確指定名稱。規則順序要先於寬泛的密碼規則,避免請求被錯誤規則接管。
3. 處理發現與連線握手
libpq 使用 oauthissuer 存取 discovery 文件,再依伺服器要求取得 token。用戶端的 oauthissuer 必須與 HBA 中的 issuer 一致;PostgreSQL 文件指出,不一致會導致連線失敗,也能降低 mix-up attack 風險。連線字串中不要把 token 寫入日誌、程序參數或持久化設定。
4. 做 token 與角色驗證
validator 至少要檢查簽章、issuer、有效期、受眾和所需 scope,並回傳可稽核的外部身分。沒有 map 時,驗證後的使用者名稱必須與請求角色名相同;多租戶對映應採用最小權限和預設拒絕。delegateidentmapping 會跳過標準 pg_ident.conf 對映,只能在 validator 自己完成完整授權判斷時使用。
5. 遷移與回滾
先在非生產環境驗證 provider discovery、TLS、scope 和失效 token,再為小組服務增加 OAuth HBA 規則。雙軌期間分別統計成功率、過期 token、issuer 不匹配和角色對映拒絕。確認連線池、作業和維運腳本都能刷新 token 後擴大範圍。回滾只需撤銷 OAuth 規則或切回 SCRAM,保留舊憑據直到所有連線池完成切換。
高品質示範答案
我會先畫出四個主體:服務程序是 client,外部身分平台是 authorization server,PostgreSQL 是 resource server,資料庫角色是本地授權物件。伺服器用 pghba.conf 的 oauth 方法指定 issuer、scope 和 validator,並把 token 身分對映到租戶角色;不使用 delegateidentmapping,除非 validator 能證明角色授權。用戶端只保存短期 token 取得所需的安全設定,使用 oauthissuer 觸發 discovery,強制 TLS 並禁止在日誌記錄 token。灰度階段保留 SCRAM 規則,按租戶和連線池逐步切換,監控 issuer、scope、過期和對映失敗;發現錯誤時刪除 OAuth 規則即可回滾。這樣既利用 PostgreSQL 18 的原生驗證能力,也把身分簽發、資料庫授權和遷移控制分開。
常見錯誤
- 說 PostgreSQL 會簽發 OAuth token,混淆 resource server 與 authorization server。
- 只驗證 JWT 簽章,不驗證 issuer、受眾、到期時間或 scope。
- 認為 issuer 只要網域相同即可,忽略 discovery 中的逐字比對。
- 直接啟用
delegateidentmapping,卻沒有說明 validator 如何做角色授權。 - 將 bearer token 放入連線日誌、錯誤追蹤或長期環境變數。
- 一次刪除 SCRAM,導致連線池和批次工作無法回滾。
追問與回答
issuer 為什麼必須精確比對?
用戶端會依 issuer 建構 discovery URL,並將返回文件中的 issuer 與設定比較。大小寫、格式或路徑變化都可能導致失敗;嚴格比較也能阻止用戶端被錯誤授權伺服器誘導。
沒有 map 時如何決定資料庫角色?
驗證器得到的使用者名稱必須與請求連線的角色名稱完全一致。多租戶環境通常需要明確 map,並讓不存在的對映預設拒絕,避免 token 身分自動落入高權限角色。
OAuth 失敗時如何保持可用?
保留短期有效的 SCRAM 回滾憑據,先按連線池灰度;監控按錯誤類型分組的失敗率。必要時撤銷 OAuth HBA 規則並恢復原規則,再修復 discovery、scope 或 validator 設定。