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