企业安全建设之自动化代码扫描(代码审计)
一、代碼掃描的目標
網上關于代碼掃描的介紹無一不是在推薦基于語法語義分析的代碼掃描工具,典型的代表就是fortify、Checkmarx。總結起來觀點無非是, 目前市面上有基于正則表達式和基于語義分析的兩種檢測方式,基于正則表達式的傳統代碼安全掃描方案的缺陷在于其無法很好的“理解”代碼的語義,而是僅僅把代碼文件當作純字符串處理。靜態掃描商用產品都運用了語義分析、語法分析等程序分析技術靜態分析層負責對代碼文件進行“理解”,完成語義、語法層面的分析。能進行完整數據流分析,通過分析污點傳播進行漏洞判定。
之前也使用過fortify進行自動化代碼掃描,由于誤報率太高導致推送給業務方的漏洞代碼不被重視,也使安全部門的權威性受損。業務方不可能從眾多的代碼結果中排查出漏洞代碼,所以不得不放棄fortify(fotify做代碼審計輔助工具還是不錯的)。另外一個原因是,fortify沒法自定義掃描規則,當有內部特定代碼風險的時候無法編寫規則掃描,帶來了一定的不便利性。
基于以上兩點問題,對于代碼掃描有了新目標。首先掃描準確性要高,其次要能靈活的自定義規則。經過分析發現,再厲害的語法語義掃描器也避免不了誤報,最大難點在于掃描器根本無法識別過濾函數的有效性。靜態代碼掃描要解決這個問題除非用AI來解決,這是云舒的觀點我非常贊同,等有一天AI能向人一樣閱讀代碼的時候這個問題可能會解決吧。所以決定采用基于正則表達式的代碼掃描器,我們可以掃一些代碼規范類的問題。例如:不規范函數、SQL語句拼接、redis和MongoDB未授權訪問、數據庫連接信息硬編碼、DEBUG 模式未關閉、fastjson遠程代碼執行漏洞的特定代碼等等。雖然掃描來的這些問題不一定是漏洞但一定是代碼風險也是不規范的寫法,這樣業務方也更容易接受。對于漏洞類型的代碼可以交給運行態代碼檢測工具iast去發現,iast的缺點就是需要依靠第三方測試流量可能面臨覆蓋面不全的尷尬境地,所以需要結合靜態代碼使用。
不管怎么說能發現潛在風險并且業務方能接受整改,那么我們的目的就達到了。
二、為什么不選fortify
代碼掃描器一般的掃描邏輯是圍繞尋找Source和Sink展開。Source 是污染源,有害數據的入口點。Sink 是程序執行造成危害的部分。接下來追蹤污染路徑,確定Source–Path–Sink重點看下傳進來的參數有沒有做有效過濾,邏輯再現攻擊,如果入參到最終執行函數都是可通行的那么一般都是有漏洞的。
Fortify會產生誤報的原因,對于Source函數和Sink這些都是系統自定義函數,fortify有足夠的實力可以整理出來各個語言的入口函數和執行函數列表并形成規則。但是對于過濾函數卻顯得無能為力了,主要原因是過濾規則千奇百怪通過靜態代碼的語義分析根本無法識別是否做了有效過濾。
例如,對于xss漏洞在不同場景就有不同的過濾方法,輸出到html、js、css、富文本等這些過濾規則就各式各樣,如果不是人為去審計代碼靠程序很難分析出來是否做了有效過濾。
這里通過一個掃描案例來分析fortify誤報的原因。
這里選取WebGoat的代碼作為測試代碼。
(1)這里掃描識別出來是xss漏洞代碼,并且數據流向也畫出來了。咋一看fortify還挺強大的。
(2)增加過濾函數,并對惡意參數進行過濾
(3)再次使用fortify掃描,對惡意參數已經做了有效過濾仍然報出xss漏洞,顯然這是誤報。
(4)將過濾函數添加到過濾規則明白中去,相當于告訴fortify這個函數做了有效過濾。
右鍵添加規則
(5)再次使用fortify掃描代碼,誤報解除。上圖掃描出來6個xxs漏洞,下圖掃描出來2個,上圖中過濾函數添加fotify規則白名單的代碼不再掃出來xss漏洞。
三、基于正則掃描原理分析
工欲善其事必先利其器,理解好一個器具的使用最好的方式就是理解其代碼運行的原理,這樣才能做到靈活應變。
這里以MongoDB未授權訪問漏洞為例來講解代碼掃描原理。
如果沒有對MongoDB訪問進行認證,或者沒有按照官方標準的寫法來認證的話,我們都認為是有安全風險的。
MongoDB未認證&Java原生API訪問MongoDB:
public void init(){client = newMongoClient("192.168.23.24", 27022);dataBase =client.getDatabase("duanjt");collection =dataBase.getCollection("teacher");}// 插入一條數據@Testpublic void insert() {Document doc = new Document();doc.append("name", "李四");doc.append("addr", "重慶");doc.append("likes", Arrays.asList("排球", "籃球"));// 數組collection.insertOne(doc);// 插入數據時會自動創建數據庫和**System.out.println("success");}MongoDB認證&JavaAPI接口調用:MongoClient client= null;try {MongoCredentialcredential = MongoCredential.createCredential(“username” , “dbname”, “pwd”);ServerAddress addr= new ServerAddress(“ip”, port);client = newMongoClient(addr, Arrays.asList(credential));DB db =client.getDB(MongoDBCfg.DB_SP2P);// 以下可以對db進行相關操作} catch (Exceptione) {} finally {if (client != null){client.close();}}這里通過正則的分組表達式將規則分為定位規則(定位執行函數),前置規則(一般是入參函數的規則,如果有寫了前置規則和定位規則就必須兩條規則都匹配到才能說明有代碼風險),防御規則(防御函數的規則,如果能識別出來這條規則就可以認為不存在代碼風險)
代碼掃描邏輯:
1)? 首先下載項目的git倉庫代碼并將其存儲到指定的目錄,便于接下來進行代碼掃描。
2)掃描準備工作獲取代碼基本信息
通過cloc命令將項目的基本代碼信息解析出來。例如統計有多少行代碼,有多少種類型的擴展文件,有多少個文件等。
同時在Dependencies類里面會使用mvn dependency:tree去分析項目的依賴jar包的大版本和小版本從而形成應用資產,便于出現jar依賴漏洞(如fastjson)的時候快速排查哪些應用存在漏洞依賴。
3)遍歷代碼規則掃描文件,這里使用grep命令進行文件掃描。
首先這里會掃描定位規則,掃描出來定位規則后,后面會進一步判斷前置規則和防御規則多條件判斷是否存在代碼風險。
4)開始匹配前置規則或者防御規則。
如果只寫了定位規則且匹配到了說明有代碼風險,可以是一些配置類的規則,比如csrf開關是否關閉、DEBUG模式未關閉等。
如果寫了前置規則和定位規則,要兩個規則都能匹配到才能說明有代碼風險。可以是一些需要判斷前置條件的規則,比如Cookie不安全存儲、HTTP Response Splitting等。
如果寫了防御規則,只要防御規則生效說明沒有代碼風險,比如本文分析的MongoDB未授權訪問漏洞就用到了防御規則。
在前面匹配到了定位規則(MongoClient(\s*)\((\s*)\”\w*\”)后,這里由匹配到了防御規則MongoCredential\.createScramSha1Credential\(
由于匹配到了防御規則所以這里is_vul=False可以判斷沒有代碼風險。
如果采用Java原生API訪問MongoDB沒有認證代碼,那么這里就無法匹配到防御規則因此is_vul=True,說明業務方沒有對MongoDB進行鑒權,因此可以判定為存在代碼風險。
總結
以上是生活随笔為你收集整理的企业安全建设之自动化代码扫描(代码审计)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python for循环的用法,怎么前面
- 下一篇: mysql刻度转时分秒