水平權(quán)限漏洞一般出現(xiàn)在一個(gè)用戶對(duì)象關(guān)聯(lián)多個(gè)其他對(duì)象(訂單、地址等)、并且要實(shí)現(xiàn)對(duì)關(guān)聯(lián)對(duì)象的CRUD的時(shí)候悯仙。開發(fā)容易習(xí)慣性的在生成CRUD表單(或AJAX請(qǐng)求)的時(shí)候根據(jù)認(rèn)證過的用戶身份來找出其有權(quán)限的被操作對(duì)象id,提供入口,然后讓用戶提交請(qǐng)求嗽仪,并根據(jù)這個(gè)id來操作相關(guān)對(duì)象。在處理CRUD請(qǐng)求時(shí)柒莉,往往默認(rèn)只有有權(quán)限的用戶才能得到入口钦幔,進(jìn)而才能操作相關(guān)對(duì)象,因此就不再校驗(yàn)權(quán)限了常柄±鹎猓可悲劇的是大多數(shù)對(duì)象的ID都被設(shè)置為自增整型,所以攻擊者只要對(duì)相關(guān)id加1西潘、減1卷玉、直至遍歷,就可以操作其他用戶所關(guān)聯(lián)的對(duì)象了喷市。
水平權(quán)限漏洞的原理看似簡(jiǎn)單相种,但他和開發(fā)的思維、編碼習(xí)慣剛好相反品姓,因此會(huì)經(jīng)常冒出來寝并。尤其是WAP和AJAX接口,開發(fā)者往往不把這些接口當(dāng)作HTTP請(qǐng)求看腹备,增加了很多其實(shí)不存在的有利于安全假設(shè)條件衬潦,從而導(dǎo)致更加忽視對(duì)權(quán)限的鑒別。
因?yàn)檫@類關(guān)聯(lián)對(duì)象的操作都和業(yè)務(wù)相關(guān)植酥,且接口獨(dú)立镀岛,所以很難實(shí)現(xiàn)通用的預(yù)防或解決方案,這也是這類漏洞讓人頭疼的原因之一友驮。今天在修復(fù)一個(gè)水平權(quán)限漏洞時(shí)漂羊,給開發(fā)同學(xué)介紹了下水平權(quán)限漏洞的修復(fù)方案,而開發(fā)同學(xué)又提出了一個(gè)我之前沒想過的方法卸留,因此決定一起整理出來走越。
漏洞示例:
getAddress.do?addressId=12345
攻擊者修改addressId即可得到他人的address信息。
修復(fù)方案0:
先看一個(gè)有問題的方案:將addressid改成一個(gè)具有一定長度的隨機(jī)字符串耻瑟,如5d41402abc4b2a76b9719d911017c592旨指,認(rèn)為只有有權(quán)限的人才能得到這個(gè)入口赏酥,而且不能通過加1、減1的方式預(yù)測(cè)別人的入口淤毛,因此不再做進(jìn)一步的權(quán)限檢查(很多初級(jí)的招聘頁面都是以這種方式來管理簡(jiǎn)歷的)今缚。這個(gè)方案看上去沒有問題,可是和國內(nèi)的環(huán)境結(jié)合起來就會(huì)悲劇——至少我遇到過的低淡,搜狗瀏覽器會(huì)把用戶發(fā)送的請(qǐng)求上傳到服務(wù)器上姓言,作為其搜索引擎爬蟲的爬取源,這樣爬蟲就會(huì)通告查詢操作得到相關(guān)的對(duì)象信息蔗蹋,并展示在搜索引擎上何荚,如果對(duì)象信息包含敏感內(nèi)容,則產(chǎn)生隱私泄露的安全事件猪杭。
修復(fù)方案1:
這個(gè)是最直接有效的修復(fù)方案:在web層的邏輯中做鑒權(quán)餐塘,檢查提交CRUD請(qǐng)求的操作者(通過session信息得到)與目標(biāo)對(duì)象的權(quán)限所有者(查數(shù)據(jù)庫)是否一致,如果不一致則阻斷皂吮。這個(gè)方案實(shí)現(xiàn)成本低戒傻、能確保漏洞的修復(fù)質(zhì)量,缺點(diǎn)是增加了一次查庫操作蜂筹。我之前一直用這種方案來對(duì)已發(fā)生的水平權(quán)限漏洞做緊急修復(fù)需纳。
修復(fù)方案2:
我認(rèn)為最正規(guī)的方案:把權(quán)限的控制轉(zhuǎn)移到數(shù)據(jù)接口層中,避免出現(xiàn)select/update/delete ... where addressID=#addressID#的SQL語句艺挪,使用selectt/update/delete... where addressID=#addressID# and ownerId=#userId#來代替不翩,要求web層在調(diào)用數(shù)據(jù)接口層的接口時(shí)額外提供userid,而這個(gè)userid在web層看來只能通過seesion來取到麻裳。這樣在面對(duì)水平權(quán)限攻擊時(shí)口蝠,web層的開發(fā)者不用額外花精力去注意鑒權(quán)的事情,也不需要增加一個(gè)SQL來專門判斷權(quán)限——如果權(quán)限不對(duì)的話津坑,那個(gè)and條件就滿足不了妙蔗,SQL自然就找不到相關(guān)對(duì)象去操作。而且這個(gè)方案對(duì)于一個(gè)接口多個(gè)地方使用的情況也比較有利国瓮,不需要每個(gè)地方都鑒權(quán)了灭必。但這個(gè)方案的缺陷在于實(shí)現(xiàn)起來要改動(dòng)底層的設(shè)計(jì),所以不適合作為修復(fù)方案乃摹,更適合作為統(tǒng)一的控制方案在最開始設(shè)計(jì)時(shí)就注意這方面的問題。
修復(fù)方案3:
今天開發(fā)同學(xué)提到一種我之前沒想到過的方式跟衅,實(shí)際上是對(duì)方案1的修改:在生成表單時(shí)孵睬,增加一個(gè)token參數(shù),而token=md5(addressId+sessionId+key)伶跷;在處理請(qǐng)求時(shí)掰读,用addressId秘狞、sessionId和key來驗(yàn)證token。這樣的方案實(shí)現(xiàn)起來很簡(jiǎn)單蹈集,又不增加額外的SQL查詢開銷烁试,看起來比方案1更好÷K粒可我之前沒有想到過這種方案减响,乍一看又是把鑒權(quán)和操作這一串同步的操作異步化了(實(shí)際上是在生成表單的時(shí)候鑒權(quán)并生成token,然后在操作時(shí)只驗(yàn)證token而不鑒權(quán))郭怪,所以一時(shí)還拿不準(zhǔn)這樣會(huì)不會(huì)有啥問題~不過我是想了半天也找不到漏洞哈~
修復(fù)方案4:
把這種屬主支示、權(quán)限、對(duì)象鄙才、操作的場(chǎng)景抽象成一個(gè)統(tǒng)一的框架颂鸿,在框架內(nèi)一個(gè)地方實(shí)現(xiàn)權(quán)限的管理和檢查。當(dāng)然這個(gè)說起來有點(diǎn)扯淡了攒庵,在產(chǎn)品設(shè)計(jì)階段是不是有人愿意花大成本來設(shè)計(jì)相關(guān)框架呢嘴纺?如果最開始沒有框架,那么什么時(shí)候愿意花更大的成本去遷移呢浓冒?我想最終還是會(huì)按方案1栽渴、2、3來吧裆蒸。
另外的方法:
- 1熔萧、可對(duì)ID加密
- 2、使用GUID
- 3僚祷、每一個(gè)信息增加一個(gè)發(fā)布人的字段佛致,修改的人必須與發(fā)布的人為同一個(gè)人才可以訪問