API安全風(fēng)險(xiǎn)主動(dòng)感知與度量探索
0x1 背景
隨著應(yīng)用越來(lái)越多,每天大量的代碼變更會(huì)帶來(lái)很多潛在的安全風(fēng)險(xiǎn),如果這些風(fēng)險(xiǎn)沒(méi)有被挖掘出來(lái)帶病上線,那我們暴露出去的風(fēng)險(xiǎn)就會(huì)越來(lái)越多,如何在代碼變更后及時(shí)的感知到這些風(fēng)險(xiǎn)成為非常重要的事情,只有及時(shí)的感知,才能確保風(fēng)險(xiǎn)能得到檢測(cè)和確認(rèn),而目前我們尚沒(méi)有這樣的機(jī)制來(lái)確保代碼變更產(chǎn)生風(fēng)險(xiǎn)時(shí)第一時(shí)間展示出來(lái)并布置更多的跟進(jìn)處理措施,這樣就會(huì)不斷的有新的風(fēng)險(xiǎn)暴露出去。
0x2 及時(shí)全面
當(dāng)src又又收到外部白帽子提交的漏洞時(shí),復(fù)盤(pán)大會(huì)上我們?cè)撛趺凑f(shuō)呢?
- 這個(gè)功能點(diǎn)/api不知道啥時(shí)候上線的
- 這個(gè)功能點(diǎn)當(dāng)時(shí)測(cè)試的沒(méi)問(wèn)題啊(測(cè)試case、測(cè)試流量都在呢,那這個(gè)為什么沒(méi)測(cè)試到?每個(gè)請(qǐng)求對(duì)應(yīng)測(cè)試的是哪個(gè)類型的漏洞)
- 這個(gè)漏洞修復(fù)了啊,代碼不知道啥時(shí)候回滾了,orz
- 這個(gè)當(dāng)時(shí)活太多沒(méi)來(lái)得及測(cè),orz
- 自動(dòng)化工具沒(méi)有覆蓋這個(gè)漏洞的檢測(cè)能力(那么我們的自動(dòng)化檢測(cè)工具提供了哪些測(cè)試能力能列出來(lái)嗎,這塊的檢測(cè)能力有改進(jìn)空間嗎?)
以上回復(fù)基本都是因?yàn)闆](méi)測(cè)到、沒(méi)來(lái)的及測(cè),總結(jié)下就是兩個(gè)很關(guān)鍵的點(diǎn)沒(méi)有得到保障
- 測(cè)試覆蓋度
- 測(cè)試時(shí)效性
綜上,當(dāng)應(yīng)用更新時(shí)只有及時(shí)全面的進(jìn)行安全測(cè)試才能確保應(yīng)用是相對(duì)安全的,那么及時(shí)和全面就分別對(duì)應(yīng)測(cè)試時(shí)效性和測(cè)試覆蓋度
0x201 測(cè)試覆蓋度
先說(shuō)下測(cè)試覆蓋度,安全測(cè)試和業(yè)務(wù)(質(zhì)量)測(cè)試(QUALITY ASSURANCE)同學(xué)的工作性質(zhì)有點(diǎn)類似,如果有個(gè)功能點(diǎn)或者api沒(méi)測(cè)試到根據(jù)墨菲定律這個(gè)點(diǎn)就很容易會(huì)出現(xiàn)問(wèn)題,那么如何避免這個(gè)問(wèn)題呢,那就是需要有平臺(tái)有數(shù)據(jù)來(lái)量化測(cè)試覆蓋度,這個(gè)平臺(tái)有多少api,測(cè)試了多少,測(cè)試了多少不同類型的case,測(cè)試覆蓋度依賴于以上數(shù)據(jù)。
0x202 測(cè)試時(shí)效性
如果每次研發(fā)同學(xué)發(fā)布了新的代碼,安全同學(xué)如果都是一年以后來(lái)檢查這些代碼有沒(méi)有新的風(fēng)險(xiǎn)那安全檢測(cè)的意義好像就變低了,當(dāng)然現(xiàn)實(shí)中是不可避免的人力不足,比如一個(gè)安全同學(xué)負(fù)責(zé)成百上千個(gè)應(yīng)用的安全,如果沒(méi)有好用的自動(dòng)化工具那么安全同學(xué)其實(shí)是很難應(yīng)付的過(guò)來(lái),安全測(cè)試的時(shí)效性就很難保障,目前集團(tuán)有非常棒的掃描平臺(tái)來(lái)支持我們做白盒掃描/黑盒掃描,同時(shí)目前iast模式的灰盒測(cè)試也在推廣中了,這些都是非常棒的實(shí)踐。
0x3 風(fēng)險(xiǎn)度量
度量的目的是讓我們能夠清楚的知道我們的工作重點(diǎn)應(yīng)該在哪里,不能為了度量而度量,度量或者分析后面應(yīng)該跟進(jìn)很多安全動(dòng)作,比如新增了接口就需要及時(shí)的進(jìn)行安全測(cè)試,這樣就能確保每個(gè)新增api及時(shí)的得到安全測(cè)試,這樣就能覆蓋全部的api,同時(shí)保證了時(shí)效性。要確保覆蓋度,最重要的一點(diǎn)就是我們需要知道我們的分子、分母分別是什么。不同的應(yīng)用對(duì)外提供服務(wù)的方式不一樣,基于目前B/S、C/S架構(gòu)來(lái)講,目前絕大多數(shù)風(fēng)險(xiǎn)在S端對(duì)應(yīng)的后端應(yīng)用上,目前對(duì)公網(wǎng)開(kāi)放應(yīng)用絕大多數(shù)還是通過(guò)rest-api的方式提供服務(wù),后端服務(wù)除了api還有大量的rpc接口,目前來(lái)看webx、springboot、nodejs等框架類應(yīng)用普及率越來(lái)越高,那么我們就拿webx為例來(lái)分享下如何做到應(yīng)用風(fēng)險(xiǎn)可見(jiàn),那我們思考下,一個(gè)應(yīng)用在merge代碼的時(shí)候可能會(huì)帶來(lái)哪些安全問(wèn)題,針對(duì)使用最多的java應(yīng)用,我總結(jié)了兩點(diǎn)
1 更新了pom文件,引入/消除了新的存在問(wèn)題的二/三方組件
2 api或者api代碼調(diào)用鏈發(fā)生了變化
理論上只要我們分析出以上兩個(gè)變更就可以非常清楚的知道一次commit到底會(huì)不會(huì)帶來(lái)新的風(fēng)險(xiǎn),對(duì)于一些特殊場(chǎng)景,比如api下線,不僅僅意味著風(fēng)險(xiǎn)的消亡,同樣意味著我們需要去更新我們的資產(chǎn)庫(kù)標(biāo)記相應(yīng)的api已下線。
0x301 覆蓋率中的變化的分母
要確保一個(gè)應(yīng)用中的api/rpc接口全部得到測(cè)試,我們就需要獲取到一個(gè)應(yīng)用中包含的全部api/rpc接口,這是我們計(jì)算測(cè)試覆蓋度的分母,而且隨著應(yīng)用代碼的迭代這個(gè)分母是變化的,這個(gè)分母的變化就會(huì)帶來(lái)風(fēng)險(xiǎn)。
pom里更新組件帶來(lái)的問(wèn)題目前基于漏洞庫(kù)已經(jīng)基本上覆蓋掉了,那我們說(shuō)下第二點(diǎn) api層面的變更和api調(diào)用鏈的變化
從上圖我們舉個(gè)栗子來(lái)講,先從commit1和commit2來(lái)講下,假設(shè)commit1的時(shí)候我們通過(guò)自動(dòng)化、人工確認(rèn)應(yīng)用是相對(duì)安全的了,那我們標(biāo)記應(yīng)用當(dāng)前的狀態(tài)是 safe,當(dāng)監(jiān)控到應(yīng)用有merge時(shí),也就是應(yīng)用處于commit2狀態(tài)時(shí)我們通過(guò)自動(dòng)化分析發(fā)現(xiàn)api還是3個(gè),但是api2的調(diào)用鏈上某個(gè)方法發(fā)生了變化,這時(shí)候我們就需要標(biāo)注出當(dāng)前應(yīng)用因?yàn)榇a更新新增的風(fēng)險(xiǎn)是 api2的調(diào)用鏈上某個(gè)方法發(fā)生變更了,這時(shí)候就需要我們?nèi)ゴ_認(rèn)是否有新增風(fēng)險(xiǎn)。
再比如commit2到commit3 ,新增了一個(gè)api4,這時(shí)候 新增的這個(gè)api4 就是需要我們?nèi)リP(guān)注的風(fēng)險(xiǎn)。
按照上面的邏輯,我們應(yīng)該可以把新增的風(fēng)險(xiǎn)梳理出來(lái),主要是防止新增風(fēng)險(xiǎn)慢慢變成存量風(fēng)險(xiǎn),不積硅步無(wú)以至千里,哎,好像不大應(yīng)景。。。
就像前面說(shuō)的一個(gè)應(yīng)用對(duì)外提供服務(wù)基本就兩種方式,一個(gè)是rest-api,一個(gè)是rpc接口,也就是對(duì)一個(gè)應(yīng)用而言除去運(yùn)行環(huán)境下,暴露的攻擊面就是各種接口了, 這就是一個(gè)應(yīng)用全部的分母,也就是我們保護(hù)的對(duì)象。
想要梳理一個(gè)應(yīng)用包含哪些api/rpc接口方法有很多,基于流量、AST分析、插樁、swagger插件都是可以的,從源碼層面分析最簡(jiǎn)單的應(yīng)該是基于AST來(lái)獲取,針對(duì)常規(guī)的springboot項(xiàng)目或者pandoraboot項(xiàng)目,通過(guò)AST很容易分析出其中的api變化,當(dāng)然如果做的精致一些可以基于源碼輸出類似swagger組件輸出一樣的數(shù)據(jù),接口、入?yún)⒚?、入?yún)㈩愋?、返回類型、返回如果是一個(gè)對(duì)象、對(duì)象的屬性有哪些,這些信息對(duì)安全測(cè)試而言同樣都是非常有用的信息。
0x302 誰(shuí)來(lái)保證分子
要想保證分子是更加接近分母就需要思考以下問(wèn)題,
- 這個(gè)應(yīng)用有多少api?(資產(chǎn)庫(kù))
- 這些api測(cè)試了嗎?
2.1 誰(shuí)測(cè)試的?
2.2 什么時(shí)候測(cè)試的?
2.3 測(cè)試時(shí)候的代碼和現(xiàn)在的代碼一樣嗎?也就是現(xiàn)在的api還是當(dāng)時(shí)的api嗎?不會(huì)更新了吧?不會(huì)回滾了吧?
2.4 測(cè)試記錄還在嗎?(怎么證明你測(cè)了?。。。?br>2.5 測(cè)試了哪些姿勢(shì)?(這么敏感的接口居然沒(méi)測(cè)試過(guò)越權(quán)?自動(dòng)化工具不支持?) - 代碼更新以后風(fēng)險(xiǎn)能感知到嗎?
- 感知到以后需要哪些能力支持我們?nèi)プ詣?dòng)化確認(rèn)這些風(fēng)險(xiǎn)?黑盒、白盒、人工、iast
當(dāng)前最實(shí)際的問(wèn)題是線上運(yùn)行的成千上萬(wàn)的應(yīng)用中包含的漏洞該怎么挖掘出來(lái),同時(shí)怎么防止新增風(fēng)險(xiǎn)變成存量風(fēng)險(xiǎn)。這兩個(gè)問(wèn)題中更重要的應(yīng)該是怎么防止新增風(fēng)險(xiǎn)變成存量風(fēng)險(xiǎn),否則我們就會(huì)陷入一直在處理存量風(fēng)險(xiǎn)的困境。那么讓新增風(fēng)險(xiǎn)可見(jiàn)就變成了一個(gè)非常緊急且重要的事情。要實(shí)現(xiàn)風(fēng)險(xiǎn)可見(jiàn)需要幾個(gè)關(guān)鍵點(diǎn)。
風(fēng)險(xiǎn)可見(jiàn)的關(guān)鍵點(diǎn):
- 自動(dòng)化分析是否有新增api
- 自動(dòng)化分析原有api調(diào)用鏈以及調(diào)用鏈上各個(gè)方法是否有變更
而要實(shí)現(xiàn)第二點(diǎn)就需要把每個(gè)api對(duì)應(yīng)的調(diào)用鏈和調(diào)用鏈上的各個(gè)方法統(tǒng)一存儲(chǔ)進(jìn)來(lái)方便進(jìn)行比對(duì)。
0x4 新增風(fēng)險(xiǎn)分析實(shí)踐
此圖為在猿輔導(dǎo)打工時(shí)團(tuán)隊(duì)產(chǎn)出的腦圖(手動(dòng)感謝andr01la、l4yn3liu、T00ls01)
基于上圖拿內(nèi)部某個(gè)應(yīng)用進(jìn)行實(shí)踐,通過(guò)實(shí)踐我們可以輸出代碼變更時(shí)是否有新的api產(chǎn)生,是否有api對(duì)應(yīng)的調(diào)用鏈的變化
0x401 基于ast分析api/rpc接口
0x40101 rest-api
使用AST梳理api可以根據(jù)類或者方法注解進(jìn)行查找,最常見(jiàn)的注解為以下幾類
比如針對(duì)以下代碼通過(guò)分析注解也可以獲取到類似swagger的數(shù)據(jù)輸出
0x40102 hsf/dubbo
0x402 調(diào)用鏈關(guān)系獲取
從某個(gè)api開(kāi)始分析
/contract/buy/queryInfoByEmail.json對(duì)應(yīng)的入口方法是queryInfoByEmail,從該方法做為開(kāi)始我們通過(guò)codeQL獲取其調(diào)用鏈上的各個(gè)方法
以上我們通過(guò)批量、遞歸操作就可以獲取到一個(gè)api對(duì)應(yīng)的入口方法開(kāi)始其中調(diào)用鏈上的各個(gè)方法和在代碼中的索引值,知道了索引值也就可以從源碼中獲取到每個(gè)方法的代碼塊和調(diào)用位置,就可以獲取到類似以下的信息
如此就可以獲取到某個(gè)應(yīng)用某個(gè)commitid下api對(duì)應(yīng)的調(diào)用鏈信息和每個(gè)方法的具體代碼了,當(dāng)應(yīng)用被更新時(shí),重新執(zhí)行以上流程就可以獲取到在新的commitid下api信息以及調(diào)用鏈信息,對(duì)信息進(jìn)行比對(duì)就可以獲取到差異,而風(fēng)險(xiǎn)就存在于變化之中。
0x403 產(chǎn)品化
以上我們可以獲取到api以及api調(diào)用上的變化,那么這些變化就是需要確認(rèn)的風(fēng)險(xiǎn)點(diǎn),通過(guò)產(chǎn)品或者平臺(tái)將這些信息展示出來(lái)我們就可以很直觀的看到風(fēng)險(xiǎn)點(diǎn),下一步就是確認(rèn)這些風(fēng)險(xiǎn)是否是需要進(jìn)一步處理的,最原始的方法就是人工確認(rèn),最起碼這就有了一個(gè)可以做動(dòng)作的入口。同時(shí)如果通過(guò)自動(dòng)化手段可以把a(bǔ)pi、api調(diào)用鏈變化信息、調(diào)用鏈中每個(gè)方法的源碼、api測(cè)試樣例都能在一套平臺(tái)里展示出來(lái),那都將極大的提升審查漏洞、復(fù)核漏洞的效率。
0x5 需要的能力
0x501 API發(fā)現(xiàn)能力
一部分通過(guò)AST解析獲取代碼中的api,另一部分來(lái)自于流量清洗獲取。 這兩種方式各有優(yōu)劣,ast準(zhǔn)確率高但是缺少請(qǐng)求樣例,流量中解析需要做歸一化處理,如果處理不好一個(gè)應(yīng)用下就變成了有十幾萬(wàn)API,優(yōu)勢(shì)就是有請(qǐng)求樣例(request、response),如果ast和流量解析出來(lái)的請(qǐng)求能統(tǒng)一起來(lái),那么我們就可以獲取到指定應(yīng)用下有多少api、api入口類和方法、請(qǐng)求樣例、對(duì)應(yīng)的響應(yīng)樣例,這樣一個(gè)應(yīng)用下基礎(chǔ)信息就有了。后續(xù)每個(gè)api會(huì)透出什么信息、是哪類敏感信息就都可以做了。
0x502 檢測(cè)能力量化
不管是所謂的大廠還是小廠,真正接觸過(guò)后才知道很多應(yīng)用其實(shí)是根本沒(méi)有做過(guò)安全測(cè)試的,有些是沒(méi)有流量觸發(fā)不了掃描,有些是post接口擔(dān)心影響業(yè)務(wù)不敢掃,假如有了前面的api列表信息,并且黑盒能夠標(biāo)注哪些做過(guò)檢測(cè)了,檢測(cè)的漏洞類型是什么都記錄下來(lái),那么我們就可以很清晰的知道咱們應(yīng)用哪些漏洞類型還沒(méi)有做檢測(cè),沒(méi)有做的檢測(cè)就需要我們黑白盒、安全運(yùn)營(yíng)工程師一起努力來(lái)打造、提升檢測(cè)能力;另一方面外部提交漏洞時(shí)也可以快速的復(fù)盤(pán)知道這個(gè)api我們內(nèi)部到底有沒(méi)有測(cè)試到這個(gè)api、何時(shí)、何人測(cè)試的。
0x503 接口變更感知能力
前面同樣鋪墊過(guò)了,所有的變化都是需要能被感知到的,并且需要有能力檢測(cè)到哪些變更會(huì)帶來(lái)風(fēng)險(xiǎn),帶來(lái)的風(fēng)險(xiǎn)需要誰(shuí)去判斷是否真正存在漏洞,誰(shuí)來(lái)卡點(diǎn)?是統(tǒng)一在一個(gè)平臺(tái)比如soc處理,還是需要安全工程師來(lái)回切換,比如接口是mtop發(fā)布然后就需要去mtop看接口信息、看入?yún)?、出參?br>是不是可以根據(jù)過(guò)往數(shù)據(jù)來(lái)分析呢?比如新增了一個(gè)api返回的數(shù)據(jù)類型和另一個(gè)已發(fā)布接口的數(shù)據(jù)類型是一樣的,比如都是某個(gè)Order類型的對(duì)象,那是不是就可以作為參考呢?
0x6 總結(jié)
以上是最近在安全運(yùn)營(yíng)工作中在遇到一些迷惑之處的思考,大佬們有其他意見(jiàn)和建議也可以在下方留言或者wx(m0l1ce)