許多 Web 框架為了開發方便,提供了「大量賦值 (Mass Assignment)」功能,允許開發者將 HTTP 請求中的參數直接、自動地綁定到後端的物件模型上。然而,若未謹慎過濾,這個便利的功能就可能成為嚴重的安全漏洞,讓攻擊者得以竄改他們本不應有權限修改的資料欄位。
什麼是大量賦值漏洞?
大量賦值漏洞發生在,當應用程式的後端 API 端點,無差別地接受了使用者請求中所有的欄位,並將它們直接對應更新到資料庫的物件模型上時。
這意味著,即使某個欄位(例如 isAdmin
, account_balance
)沒有出現在前端的表單中,攻擊者也可以透過手動建構 HTTP 請求,擅自加入並修改這些「隱藏」的敏感欄位。
攻擊原理與範例
情境:偷偷將自己變成管理員
- 分析 API 端點:攻擊者在一個網站上註冊了帳號,並使用瀏覽器開發者工具觀察「更新個人資料」功能。他發現,當他提交表單時,瀏覽器會發送一個
PUT
請求到/api/users/me
,請求的 Body 內容如下:1
2
3
4{
"nickname": "Hacker",
"bio": "I love security"
} - 發現潛在欄位:接著,他嘗試用
GET
請求訪問同一個端點/api/users/me
來獲取自己的資料,結果伺服器回傳了更多資訊:他注意到回應中有一個1
2
3
4
5
6
7{
"id": 123,
"username": "hacker_user",
"nickname": "Hacker",
"bio": "I love security",
"isAdmin": false
}isAdmin
欄位,這在更新表單中是沒有的。 - 建構惡意請求:攻擊者猜測後端可能直接將請求的 JSON 綁定到使用者物件上。於是,他使用工具(如 Postman 或 cURL)重新發送一個
PUT
請求,並在請求 Body 中手動加入了isAdmin
欄位:1
2
3
4
5{
"nickname": "Hacker",
"bio": "I love security",
"isAdmin": true
} - 攻擊成功:由於後端開發者沒有設定保護,伺服器接受了請求中的所有欄位,並將
isAdmin
的值更新為true
。攻擊者就這樣悄悄地將自己提升為管理員,取得了網站的最高權限。
風險與影響
- 權限提升:最常見的風險,普通使用者可以將自己變成管理員。
- 繞過業務邏輯:修改商品價格、帳戶餘額、訂單狀態等。
- 資料竄改:修改任何資料庫中不應由使用者直接控制的欄位。
防禦與預防措施
防禦的核心原則是:永遠不要信任來自客戶端的資料結構,只接受你預期要處理的欄位。
1. 使用白名單 (Allow-listing) 而非黑名單 (Deny-listing)
- 白名單(推薦):明確定義一個列表,只允許列表中的欄位被更新。所有不在列表中的欄位都會被忽略。這是最安全的方法。
- 黑名單(不推薦):定義一個列表,禁止列表中的敏感欄位(如
isAdmin
)被更新。這種方法較危險,因為開發者可能會忘記將新的敏感欄位加入黑名單。
2. 使用資料傳輸物件 (Data Transfer Objects, DTO)
- 建立一個獨立的 DTO 層,專門用來接收來自客戶端的請求。這個 DTO 物件只包含允許使用者修改的屬性。
- 在後端邏輯中,先將請求內容綁定到 DTO,驗證後,再手動將 DTO 中的資料賦值給實際的資料庫模型 (Entity)。這樣可以完全避免意外的屬性綁定。
3. 利用框架內建的保護功能
- 許多現代框架都意識到了這個問題,並提供了內建的防護機制。例如,在 Ruby on Rails 中稱為 “Strong Parameters”。務必詳閱並正確使用您所用框架的安全功能。
說些什麼吧!