F1系統權限漏洞
最近有三個資安研究員 Ian Carroll、Sam Curry 與 Gal Nagli 發布了與 F1 相關系統有關的漏洞系列文,第一篇是在講跟駕照分類系統有關的漏洞(還有二三篇但還沒出來)。
要參加 F1 的比賽,需要有個 FIA super licence,而 FIA 對於車手有分不同等級,需要透過一個系統提出資料並申請更新等級的狀態。
由於這個系統是 public 的,所以任何人都可以上去註冊一個帳號(這也滿合理)。
在更新資料的時候,會用一個 PUT 的 API 如 PUT /api/users/12345,body 裡面則是放你要更新的東西,如姓名等等,看起來也很正常。
但是呢,他們注意到在 response 中多了個 roles 的欄位,於是靈機一動想說:「會不會這個 API 有 mass assignment 漏洞呢…」。
所謂的 mass assignment 呢,就是後端在更新資料時偷懶沒指定欄位,直接把請求中所有的欄位都更新進去資料庫,以 JavaScript 來講就類似於 session.user.update(req.body) 這種感覺,你給我什麼我就更新什麼。
因此,儘管前端沒有提供更新 role 的功能,只要自己在後端傳入 roles 這個欄位,就會一併更新,並且取得相關權限。這種 mass assignment 的漏洞並不少見,而且在某些程式語言上滿常發生。
但要更新的話,要先知道 roles 裡面到底要傳什麼,於是他們就在前端程式碼裡找找看線索,由於前端原本就有檢查 roles 的程式碼,因此可以推測出 roles 的結構,並且反向構造出合法的 payload。
接著就只要在 PUT 請求裡面塞入符合格式的 roles,就拿到了 admin 權限,剩下就想幹嘛就幹嘛了。
要修這種 mass assignment 漏洞也很簡單,就是後端明確寫出到底有哪些欄位可以更新就沒事了,就不會更新到不該更新的東西。
這個漏洞的根本原因就是 mass assignment 而已,不是什麼「沒有金鑰就可以更新內容」,我剛登進去看過了,需要一個 cookie 才能 update 自己的資料。也不是什麼「權限只放在前端」,前端出現檢查 role 的程式碼再正常不過,但重點是不能只有前端檢查,後端也要檢查。
前端檢查權限本來就沒什麼問題,程式碼出現 role 相關字串如 admin 也是再正常不過,不然你前端怎麼知道哪些要顯示哪些不顯示。雖然也是有一派做法是後端先做處理,傳個支援的 feature 列表啦,不會在前端直接檢查 role,但我覺得兩種都行。
前端的檢查原本就只是拿來增進使用者體驗,真正防範的地方一定得做在後端。只看前端程式碼的話,你也不會知道後端有沒有做驗證,所以光看前端也看不出什麼端倪。
站在資訊洩漏的角度來講,當然是全部在後端處理最好,使用者不該看到的,連 HTML 都不要傳給他。但問題是在現在這個前後端分離的時代,基本上不太可能,前端的 codebase 都跟後端完全分開了,你要動態決定前端的 response 成本有點高,因此後端 API 做自己的檢查,前端也做檢查決定哪些顯示哪些不顯示,是很常見的做法(有講錯歡迎打臉)。
評論