OWASP Top 10 API Security是由全球知名的非營利資安組織 OWASP 所統整發布的指南,列出了目前現代 API 架構中最常見、最具破壞力的十大安全風險。而和身分與存取控制 (API 1, 2, 3, 5)相關的有:失效的身份驗證,失效的功能等級授權,失效的物件等級授權,失效的物件屬性等級授權。
這一組風險構成了 API 安全的核心存取防護網。它們全都在處理同一個核心議題:「發起請求的客戶端是誰?」以及「他們到底被允許做什麼?」。這類漏洞的共通點是它們的發生通常是因為開發人員對「使用者」與「權限邊界」的追蹤或驗證不夠嚴謹所導致。
- API2:2023 (失效的身份驗證): 這是最外層的守門員,負責確認「你是誰」,防止帳號被暴力破解或劫持。
- 三個層級的授權 (API5, API1, API3): 當確認身分後,系統接著由大到小檢查權限。審查該使用者能不能使用這個功能端點 (API5)、能不能操作這個資料物件 (API1),以及能不能讀寫物件裡的特定屬性/欄位 (API3)。
1. API5:2023 失效的功能等級授權 (BFLA) :攻擊者透過猜測網址或變更 HTTP 方法(例如從 GET 改為 DELETE),成功呼叫了他們根本不該有權限存取的 API 端點或功能(例如一般用戶越權使用管理員專屬的 API)。
2. API1:2023 失效的物件等級授權 (BOLA) :攻擊者在擁有 API 存取權的情況下,透過竄改請求中的「物件 ID」,越權存取、修改或刪除他們原本不該有權限接觸的其他使用者資料。
3. API3:2023 失效的物件屬性等級授權 (BOPLA) :API 沒有正確限制使用者對物件「內部特定屬性」的權限,導致 API 回傳了不該讓人看到的敏感欄位(過度資料暴露),或是允許使用者越權修改內部設定欄位(大量指派)。
Broken Authentication
失效的身份驗證,是由於身分驗證機制通常暴露在外部,加上開發人員對安全邊界的誤解與實作的複雜性,使其成為攻擊者容易下手的目標。一旦驗證機制被攻破,攻擊者就能完全控制受害者的帳號、讀取個人機密資料,甚至代表受害者執行敏感操作,而系統往往無法分辨這些行為是否來自合法使用者。
當 API 出現以下設計缺陷時,就可能產生此漏洞:
- 未防範暴力破解或憑證填充 (Credential stuffing),缺乏驗證碼 (CAPTCHA) 或帳號鎖定機制。
- 允許使用弱密碼,或以明文、弱雜湊 (weakly hashed) 的方式儲存密碼。
- 權杖 (Token) 管理不當,例如:在 URL 中傳送權杖、未驗證 JWT 的過期時間與真實性,或接受未簽署的 JWT
{"alg":"none"}。 - 允許變更電子郵件或密碼等敏感操作,卻未要求使用者再次輸入密碼確認身分。
- 微服務之間缺乏驗證機制。
攻擊範例
範例一:利用 GraphQL 批次查詢繞過速率限制 (Bypassing Rate Limiting)
- 情境背景: 某個 API 為了防止登入遭到暴力破解,實作了嚴格的速率限制,規定每分鐘只能發出 3 次登入請求。如果憑證正確,API 會回傳一個驗證權杖供後續使用。如下
POST /graphql
{
"query":"mutation {
login (username:\"<username>\",password:\"<password>\") {
token
}
}"
}
- 漏洞解釋: 儘管系統限制了「請求次數」,但攻擊者利用了 GraphQL 的「查詢批次處理 (query batching)」特性。他們將大量的密碼猜測打包進單一一個 API 請求中發送。這導致伺服器在收到這一個請求時,同時處理了成千上萬次的帳號密碼比對。藉由這種方式,攻擊者成功繞過了每分鐘 3 次的限制,大幅加快了暴力破解受害者帳號的速度。如下
POST /graphql
[
{"query":"mutation{login(username:\"victim\",password:\"password\"){token}}"},
{"query":"mutation{login(username:\"victim\",password:\"123456\"){token}}"},
{"query":"mutation{login(username:\"victim\",password:\"qwerty\"){token}}"},
...
{"query":"mutation{login(username:\"victim\",password:\"123\"){token}}"},
]
範例二:缺乏重新驗證導致的帳號劫持 (Account Takeover via Email Update)
- 情境背景: 某 API 提供更新帳號關聯電子郵件的功能,但該 API 在執行此操作時,並沒有要求使用者輸入當前密碼來確認身分。
- 漏洞解釋: 如果攻擊者有辦法竊取到受害者的驗證權杖 (auth token),他們就可以輕易接管該帳號。攻擊步驟如下:首先,攻擊者使用竊取來的權杖呼叫更新電子郵件的 API,將受害者的信箱改為攻擊者自己控制的信箱。接著,攻擊者啟動「忘記密碼」的恢復流程,由於信箱已經被替換,系統會將密碼重設連結寄給攻擊者。最終,攻擊者就能成功重設密碼並完全佔有該帳號。如下
PUT /account
Authorization: Bearer <token>
{ "email": "<new_email_address>" }
Broken Function Level Authorization/BFLA
失效的功能等級授權,這個漏洞是指「API 沒有正確檢查使用者的身分權限,導致一般使用者(甚至是匿名訪客)能夠執行只有高權限使用者(如管理員)才能執行的敏感功能」。
現代的 API 架構高度結構化且容易預測(例如遵循 RESTful 規範),攻擊者很容易透過猜測、修改網址(URL)或改變 HTTP 方法(例如從讀取的 GET 改成刪除的 DELETE)來測試 API。如果後端程式碼或設定檔沒有落實權限控管,攻擊者就能直接越權操作,導致資料外洩、篡改或系統被控制。
攻擊範例
範例1:利用未授權的 API 建立管理員邀請函
- 正常流程: 這是一個設計為「只能透過邀請加入」的應用程式。當一個被邀請的人透過手機 App 註冊時,App 會在背後呼叫一個 API:
GET /api/invites/{invite_guid},用來讀取這張邀請函的詳細資訊(例如:被邀請人的 Email 以及被賦予的權限角色)。 - 攻擊者的手法:
- 攻擊者攔截並觀察了上述這個合法的
GET請求。 - 攻擊者發揮想像力並推測:既然有「讀取」邀請函的 API,後端很可能也有一個「建立」新邀請函的 API。
- 於是,攻擊者嘗試將 HTTP 方法從
GET改成POST(代表新增),並將網址修改為POST /api/invites/new。 - 此外,攻擊者在請求的 JSON 資料中寫入了自己的 Email,並大膽地將角色(role)指定為
"admin"(管理員):
- 攻擊者攔截並觀察了上述這個合法的
POST /api/invites/new
{
"email": "attacker@somehost.com",
"role":"admin"
}
- 漏洞所在與結果: 這個
POST /api/invites/new本來應該是只有真正的系統管理員在管理後台才能使用的功能。然而,後端 API 完全沒有去檢查呼叫這個 API 的人到底是不是管理員。最終,API 成功執行了這個請求,系統發出了一張具有管理員權限的邀請函給攻擊者。攻擊者點擊該邀請函完成註冊後,就擁有了一個具備完整控制權的管理員帳號。
範例2:猜測管理員專屬網址獲取所有用戶隱私
- 正常流程: 系統提供了一個僅限管理員使用的 API 端點:
GET /api/admin/v1/users/all。這個功能呼叫後會回傳系統中「所有使用者」的詳細機密資料。 - 攻擊者的手法: 攻擊者只是一個普通用戶,但他透過分析其他公開的 API 結構(例如看到普通用戶的網址是
/api/v1/users/me),開始「盲猜」管理員的功能路徑。他嘗試直接向GET /api/admin/v1/users/all發送請求。 - 漏洞所在與結果: 開發人員可能誤以為「只要把網址藏在
/api/admin底下,一般人不知道網址就找不到,所以很安全」(即所謂的透過隱蔽實現安全,Security through obscurity)。但當攻擊者猜中網址並發出請求時,後端程式同樣沒有實質檢查發起請求的用戶是否有管理員權限。結果,API 大方地將全系統用戶的敏感資料回傳給了攻擊者,造成嚴重的集體隱私外洩。
Broken Object Level Authorization / BOLA
失效的物件等級授權, 漏洞發生的主因是伺服器端通常不會完整追蹤客戶端的狀態,而是依賴客戶端在請求中傳送的參數(例如「物件 ID」)來決定要存取或操作哪些資料。在 BOLA 的情況下,使用者在系統設計上本來就被允許存取該 API 端點(否則就會屬於失效的功能等級授權 BFLA)。
然而,由於系統沒有在「物件等級」進行權限查核,導致攻擊者只要篡改請求(可能存在於 URL 路徑、查詢字串參數、標頭或請求 Payload 中)裡的物件 ID,就能越權存取其他使用者的物件。
一旦發生這種越權行為,可能會導致未經授權的資訊外洩、資料遺失、資料遭竄改,在特定情況下甚至能讓攻擊者完全接管別人的帳號
攻擊範例
- 電商平台資料外洩: 某電商平台提供店家查看營收圖表的功能,其 API 端點格式為
/shops/{shopName}/revenue_data.json。攻擊者透過其他端點取得所有商店名稱列表後,只需撰寫簡單的腳本替換網址中的{shopName},就能輕易獲取數千家其他商店的銷售機密數據。 - 汽車遠端控制: 某汽車品牌允許車主透過手機 API 傳送車輛識別碼 (VIN) 來遠端發動引擎和解鎖車門。但該 API 卻沒有驗證接收到的 VIN 是否真的屬於目前登入的車主。攻擊者只要輸入別人的 VIN,就能遠端控制不屬於他的汽車。
- 線上文件遭惡意刪除: 某線上儲存服務在使用者刪除文件時,會向 API 發送包含「文件 ID」的 GraphQL 請求。因為系統收到文件 ID 後就直接執行刪除而未做權限檢查,導致使用者可以透過修改 ID 來任意刪除別人的文件。
Broken Object Property Level Authorization/ BOPLA
失效的物件屬性等級授權,是當 API 允許使用者透過端點存取某個物件時,沒有正確驗證該使用者是否有權限讀取或修改該物件的「特定屬性」,就會產生這個漏洞。
這種漏洞在 REST API 中相當常見,因為這類 API 經常設計成一口氣回傳整個物件的所有屬性;而攻擊者通常只要檢查 API 回應,或透過模糊測試 (Fuzzing) 找出隱藏的屬性並嘗試修改,就能輕易發現漏洞。這可能導致機敏資料外洩、資料毀損,甚至引發權限提升與帳號接管。
攻擊範例
範例一:交友軟體的檢舉功能(讀取層級缺陷 / 資料過度暴露)
在一個交友軟體中,你看到一個行為不當的用戶(假設他的用戶 ID 是 313)。你點擊了「檢舉(Report)」按鈕,前端程式就會發送一個 API 請求給後端。依照常理,檢舉功能完成後,後端只需要告訴前端:「檢舉成功(status: success)」 以及 「謝謝您的回報(message: ‘Thank you…’)」 這樣就夠了。
假設這個 API 使用的是 GraphQL 技術。GraphQL 的特點是「由前端(客戶端)來決定後端要回傳什麼資料」。在正常的狀況下,官方 App 的程式碼可能只會要求回傳 status 和 message。
但是,攻擊者可以利用工具(例如 Burp Suite)把這段發送出去的「查詢語法(Query/Mutation)」攔截下來並動手腳。在以下程式碼中,攻擊者在 reportedUser(被檢舉的用戶)大括號裡面,自己加上了兩個原本不該由他讀取的欄位:
fullName(真實全名)recentLocation(最新精準位置)
POST /graphql
{
"operationName":"reportUser",
"variables":{
"userId": 313,
"reason":["offensive behavior"]
},
"query":"mutation reportUser($userId: ID!, $reason: String!) {
reportUser(userId: $userId, reason: $reason) {
status
message
reportedUser {
id
fullName
recentLocation
}
}
}"
}
漏洞核心是後端毫無防備地「有求必應」,當這段被修改過的請求送到後端伺服器時,後端的 API 沒有檢查:「發出檢舉的這個人,到底有沒有權限看被檢舉人的真實姓名和精準定位?」。後端系統只看到前端要這些資料,且程式碼裡可能有定義 reportedUser 物件底下確實有這些屬性,就直接把資料庫裡的敏感隱私資料通通撈出來,回傳給了檢舉者。
在交友軟體中,用戶通常只會公開暱稱或模糊距離。但透過這個漏洞,任何惡意使用者只要隨便找一個人點「檢舉」,並在封包裡加上這兩個欄位,就能肉搜出任何人的真實姓名,甚至追蹤對方的即時位置,這會帶來極大的現實生活人身安全風險。
範例二:線上租屋平台的價格竄改(未經授權的屬性修改 / 大量指派)
- 情境背景: 一個媒合「房東」與「房客」的平台,流程上需要房東透過呼叫特定的 API (
POST /api/host/approve_booking) 來核准房客的預訂,隨後系統才會向房客扣款。
{
"approved": true,
"comment": "Check-in is after 3pm"
}
- 漏洞解釋: 惡意的房東在送出核准請求時,刻意攔截並修改了原本正常的 Payload,在裡面偷偷加入了一個內部物件屬性:
total_stay_price(總住宿費用),並隨意填寫了一個更高的金額。由於該 API 沒有檢查房東是否有權限修改這個內部計費屬性,導致系統直接接收了這個惡意設定,讓無辜的房客被收取了比原本更高的費用。
{
"approved": true,
"comment": "Check-in is after 3pm",
"total_stay_price": "$1,000,000"
}
範例三:短影音平台的審查繞過(未經授權的狀態修改 / 大量指派)
- 情境背景: 某個短影音社群平台具備嚴格的內容審查機制。即使使用者的影片因為違規被系統「封鎖 (blocked)」,系統還是允許使用者透過 API 修改該影片的「描述」。如下
PUT /api/video/update_video
{
"description": "a funny video about cats"
}
- 漏洞解釋: 一名影片被封鎖的使用者,在送出修改影片描述的正常 API 請求時,於 Payload 中加入了一段惡意代碼
"blocked": false。因為 API 缺乏驗證,允許客戶端的輸入直接綁定並修改內部物件屬性,使用者便越權將自己的影片狀態從「封鎖」改成了「未封鎖」,成功繞過審查機制解鎖了違規影片。
{
"description": "a funny video about cats",
"blocked": false
}