1. 程式人生 > >水平許可權漏洞解決方案。

水平許可權漏洞解決方案。

A、水平許可權漏洞,如下圖

在這裡插入圖片描述

假設機構有 使用者A和使用者B 兩個使用者,其中A有1、2和3許可權 , 使用者B有 2 和3 的許可權,這時候假設使用者B 知道1,並給自己新增1的許可權,這時候就是水平許可權漏洞。

水平許可權漏洞一般出現在一個使用者物件關聯多個其他物件(訂單、地址等)、並且要實現對關聯物件的CRUD的時候。開發容易習慣性的在生成CRUD表單(或AJAX請求)的時候根據認證過的使用者身份來找出其有許可權的被操作物件id,提供入口,然後讓使用者提交請求,並根據這個id來操作相關物件。在處理CRUD請求時,往往預設只有有許可權的使用者才能得到入口,進而才能操作相關物件,因此就不再校驗許可權了。可悲劇的是大多數物件的ID都被設定為自增整型,所以攻擊者只要對相關id加1、減1、直至遍歷,就可以操作其他使用者所關聯的物件了。

水平許可權漏洞的原理看似簡單,但他和開發的思維、編碼習慣剛好相反,因此會經常冒出來。尤其是WAP和AJAX介面,開發者往往不把這些介面當作HTTP請求看,增加了很多其實不存在的有利於安全假設條件,從而導致更加忽視對許可權的鑑別。

因為這類關聯物件的操作都和業務相關,且介面獨立,所以很難實現通用的預防或解決方案,這也是這類漏洞讓人頭疼的原因之一。今天在修復一個水平許可權漏洞時,給開發同學介紹了下水平許可權漏洞的修復方案,而開發同學又提出了一個我之前沒想過的方法,因此決定一起整理出來。

漏洞示例:

getAddress.do?addressId=12345

攻擊者修改addressId即可得到他人的address資訊。

修復方案0:

先看一個有問題的方案:將addressid改成一個具有一定長度的隨機字串,如5d41402abc4b2a76b9719d911017c592,認為只有有許可權的人才能得到這個入口,而且不能通過加1、減1的方式預測別人的入口,因此不再做進一步的許可權檢查(很多初級的招聘頁面都是以這種方式來管理簡歷的)。這個方案看上去沒有問題,可是和國內的環境結合起來就會悲劇——至少我遇到過的,搜狗瀏覽器會把使用者傳送的請求上傳到伺服器上,作為其搜尋引擎爬蟲的爬取源,這樣爬蟲就會通告查詢操作得到相關的物件資訊,並展示在搜尋引擎上,如果物件資訊包含敏感內容,則產生隱私洩露的安全事件。

修復方案1:

這個是最直接有效的修復方案:在web層的邏輯中做鑑權,檢查提交CRUD請求的操作者(通過session資訊得到)與目標物件的許可權所有者(查資料庫)是否一致,如果不一致則阻斷。這個方案實現成本低、能確保漏洞的修復質量,缺點是增加了一次查庫操作。我之前一直用這種方案來對已發生的水平許可權漏洞做緊急修復。

修復方案2:

我認為最正規的方案:把許可權的控制轉移到資料介面層中,避免出現select/update/delete … where addressID=#addressID#的SQL語句,使用selectt/update/delete… where addressID=#addressID# and ownerId=#userId#來代替,要求web層在呼叫資料介面層的介面時額外提供userid,而這個userid在web層看來只能通過seesion來取到。這樣在面對水平許可權攻擊時,web層的開發者不用額外花精力去注意鑑權的事情,也不需要增加一個SQL來專門判斷許可權——如果許可權不對的話,那個and條件就滿足不了,SQL自然就找不到相關物件去操作。而且這個方案對於一個介面多個地方使用的情況也比較有利,不需要每個地方都鑑權了。但這個方案的缺陷在於實現起來要改動底層的設計,所以不適合作為修復方案,更適合作為統一的控制方案在最開始設計時就注意這方面的問題。

修復方案3:

今天開發同學提到一種我之前沒想到過的方式,實際上是對方案1的修改:在生成表單時,增加一個token引數,而token=md5(addressId+sessionId+key);在處理請求時,用addressId、sessionId和key來驗證token。這樣的方案實現起來很簡單,又不增加額外的SQL查詢開銷,看起來比方案1更好。可我之前沒有想到過這種方案,乍一看又是把鑑權和操作這一串同步的操作非同步化了(實際上是在生成表單的時候鑑權並生成token,然後在操作時只驗證token而不鑑權),所以一時還拿不準這樣會不會有啥問題~不過我是想了半天也找不到漏洞哈~