比黑客跑得快:如何打造實用的Web漏洞“體檢”工具
利用漏洞清除債務,盜取數據,一鍵獲取XX游戲的所有賬戶登陸權限,這些看似爽文里的“騷操作”其實早就在現實中上演。
2013年,一個自稱RedHack的黑客小組利用土耳其政府網站的Web漏洞,清除了相關人員在政府機構的債務數據。2015年,某安全研究人員公開稱,可以通過特定的注入漏洞攻破某知名汽車的網站,獲得管理權限,并竊取用戶數據。2019年,擁有超過3.5億用戶的在線游戲“XX壘之夜”被爆出一個SQL注入漏洞,可以讓攻擊者訪問所有用戶帳戶。
這些都是Web應用程序的漏洞,Web應用程序已經廣泛應用社交網絡、網上支付等各個領域,真正影響人們的生活,因此Web應用中存在的各種安全漏洞越來越引起人們的重視。
為趕在惡意人員之前發現并修復Web應用程序中的安全漏洞,安全人員需要利用各種安全測試技術識別并修復Web應用程序中的缺陷。靜態應用安全測試(Static Application Security Testing ,SAST)由于不需要運行被測程序,具有覆蓋率高、自動化程度高、可以在開發生命周期早期使用等特點,是目前被業界廣泛采用的應用安全測試技術之一。但是靜態應用安全測試作為一種針對應用安全缺陷的自動化檢測方法,本質上處理的是一個不可判定問題,理論上不可能同時做到沒有誤報也沒有漏報。
大量的誤報會使人對分析工具失去信心,而漏報會造成程序具有較高安全水位的假象,很多情況下減少誤報和減少漏報就是一對矛盾體。為盡量減少不必要的漏報和誤報,往往需要運用更復雜的分析技術,意味著更高的復雜度,因此分析的精度與分析的速度往往也是一對不可兼得的矛盾體。實用的靜態應用安全測試工具需要根據分析目標和應用場景在誤報、漏報、效率、易用性、可擴展性之間達到一個合理的平衡。
哪些缺陷類型需要“關心”
程序分析工具都有其針對的“分析目標程序屬性”(target program properties),通俗地來說“分析目標程序屬性”就是分析工具“關心哪些缺陷類型”。當前許多通用的靜態缺陷檢測工具往往強調“大而全”,強調能夠適應不同的掃描場景,強調能夠覆蓋更多的缺陷類型,實際上這里存在誤區。
實際中的程序千變萬化,對不同類型的程序,在不同的場景下,人們關注的程序屬性不一樣,對分析工具的各項要求也不一樣。靜態分析都會引入某種程度上的抽象,最有效的抽象方法需要充分利用分析目標程序屬性本身的特點。明確應用場景和分析目標程序屬性(target program properties)是設計真正實用分析工具的首要任務。
Web應用靜態安全測試的主要應用場景在開發階段而不是開發完成之后,它的重要優勢是能夠在早期就檢測出源碼中的安全漏洞,從而大大降低修復安全問題成本,成熟的大型軟件開發組織通常將其融入DevSecOps流程中。這更加要求分析工具能夠在漏報、誤報和效率之間達到合理的平衡,避免不必要地打擾和減緩正常開發流程。
Web應用靜態安全測試的分析目標程序屬性是常見的Web應用程序安全風險,核心關注的就是OWASP Top 10中列出的安全風險。下圖是最新發布的OWASP Top 10Web應用安全風險:

Web應用程序安全風險和空指針解引用、數組越界、資源泄漏、數值溢出等內存安全程序屬性有顯著區別。Web應用程序安全風險從程序語義上看更加高層(更加靠近應用層),內存安全則更加底層,更加關注程序中變量的具體取值情況。為了開發真正實用的分析工具,需要充分利用“分析目標程序屬性”的特點,選擇能夠達到最佳平衡的分析算法和策略。
Web應用安全風險程序屬性建模
為了保證靜態應用安全測試工具能夠無二義性地識別和分析目標缺陷類型,我們將目標缺陷類型的分析配置描述為靜態應用安全測試工具能夠識別的“規則”。易用且可擴展性好的Web應用靜態安全測試工具都應該做到規則和引擎分離。規則描述結構設計的過程本質上是對Web應用程序安全風險知識進行建模的過程。
OWASP Top 10列表中的Web應用安全風險可分為兩類:一類是和非正常數據流相關的安全風險,如注入、敏感信息泄露、XML外部實體、跨站腳本和不安全的反序列化。一類是和非正常控制流或狀態相關的安全風險,如失效的身份認證、失效的訪問控制、安全配置錯誤、使用含有已知漏洞的組件不足的日志和監控。我們采用兩種不同的規則描述模型來支持上述兩類Web應用安全風險:污染傳播模型和狀態機模型。
污染傳播分析
污染傳播分析又被稱作信息流分析(information-flow analysis),它是用于追蹤程序中特定數據傳播和依賴的一種數據流分析技術。污染傳播分析是Web應用安全缺陷檢測的主要方法之一,其基本思想是通過對不可信的源頭(source)引入的數據進行污染標記,跟蹤被標記的污染數據在程序中的傳播,若污染數據在進入敏感操作(sink)前未經過恰當的凈化操作(sanitizer),則表明存在潛在的安全缺陷。
污染傳播規則中的配置包括source、sanitizer、sink、安全類型等。安全類型指的是對于當前目標程序屬性來說認為肯定不會污染的類型,例如對于注入類安全風險可以認為所有的枚舉類型、布爾類型、日期類型、浮點類型等都是安全的。
對于常見的web注入安全風險,我們的解法是,提供統一的“安全方法”給開發人員調用,這些“安全方法”也是靜態分析工具能夠識別的統一的凈化操作。污染傳播分析沿控制流在每個程序位置上計算當前污染變量集合,并在污染變量間建立污染傳播依賴關系。
狀態機分析
理論上來說,Web應用安全缺陷檢測所檢查的缺陷類型都屬于時序安全屬性(temporal safety properties),安全屬性描述的是“壞的事情不會發生”一類屬性,通常可以描述成如下統一模式:“程序中某些動作或行為構成時序上的約束,一旦違背這種約束即被認為是一個缺陷”。
有限狀態機(finite state machine)是描述時序安全屬性的有效工具,污點傳播相關的缺陷類型本質上也屬于時序安全屬性,即“來自source的數據在進入sink點之前必須經過sanitizer操作,否則報告一個缺陷”(但為了缺陷報告時更好地給出污染在變量間的傳播路徑,將其采用專門的污染傳播分析進行建模)。狀態機規則中的配置包括狀態集合、狀態間的轉換集合以及各轉換所需滿足的條件集合等。
在實際的狀態機分析過程中還需要引入狀態機實例的概念,在程序中的每個分析入口函數處會創建一個狀態機實例,并沿控制流在每個程序位置上的計算它的可能狀態。如果一旦某個狀態機實例的當前可能狀態中出現了error狀態則報告一個缺陷。
分析策略選擇
從不同的抽象和近似精度角度,靜態分析方法可以區分是否流敏感(flow sensitive)、路徑敏感(path sensitive)、上下文敏感(context sensitive)、域敏感(field sensitive)、對象敏感(object sensitive)等。
具體來說流敏感需要在分析中考慮語句的執行順序,路徑敏感需要在分析中考慮分支判斷條件的組合關系并排除不可達路徑(infeasible path),上下文敏感需要在分析中考慮被調函數在不同調用點的上下文影響,域敏感需要在分析中區分同一對象的不同字段,對象敏感需要在分析中區分同一字段的不同對象。
一般來說,敏感性支持得越多,分析精度越高,實現越復雜,分析速度越慢。對于實際的靜態分析工具來說,最好的選擇是根據分析目標和應用場景的需要花最少的代價獲得最大的回報。對于Web應用程序安全風險來說,引入路徑敏感的“性價比”并不高。
污染傳播分析和狀態機分析本質上都可納入傳統的數據流分析框架,污染傳播分析在每個程序位置上計算當前污染變量集合,其對應數據流分析值為“當前污染變量集合”。狀態機分析在每個程序位置上計算狀態機實例的的當前可能變量集合,其對應數據流分析值為“狀態機實例的的當前可能變量集合”。污染變量集合和可能狀態集合的轉換函數都是滿足分配率。
傳統數據流分析基于迭代收斂完成過程內數據流分析,基于圖可達算法完成過程間數據流分析。對于本文所關注的靜態應用安全測試分析目標程序屬性來說,傳統數據流分析算法的“性價比”太低。傳統數據流分析中的迭代主要是因為實際的程序中存在循環和遞歸結構,需要通過迭代并收斂于不動點來處理控制流圖中循環回邊帶來的影響。
而實際上對于污點分析和狀態機分析(Web應用安全風險這類目標程序屬性)來說控制流圖中的回邊在實際中分析結果中的影響很小。至于圖可達算法考慮的過程間調用和返回匹配問題可以在搜索污染傳播跟蹤路徑時進行單獨處理。在不考慮循環和遞歸結構的前提下(相當于循環和遞歸只展開1次),污染傳播分析和狀態機分析可以做到接近線性復雜度O(n),n為程序中的語句條數。
函數摘要
函數摘要(function summary)是靜態分析過程中常用的一種過程間分析技術,它根據函數內分析結果生成被調函數的摘要信息,以此替代函數的實際展開,從而避免同一個函數的多次展開分析,提高函數間分析效率。函數摘要是對已展開分析過函數的“抽象和總結”,函數摘要可以看作是以函數為單位,對函數實際語義的抽象。其理想的效果是:使用函數摘要得到的計算結果等于展開實際函數調用得到的計算結果。
需要指出的是函數摘要是對函數實際語義的抽象,這種抽象必然是面向實際分析目標程序屬性特點的,應該根據不同的分析目標程序屬性設計并收集對應的函數摘要。由于靜態分析的不可判定性,通用的精確的函數摘要必然退化為函數的另一個完整實現。由于污染變量集合和可能狀態集合的轉換函數滿足分配律,面向污染傳播和狀態機的函數摘要完全可以滿足:使用函數摘要得到的計算結果=展開實際函數調用得到的計算結果。
跨應用、多語言支持
這里所謂的“跨應用”,其實用“跨掃描單元”來表述可能更為準確,“掃描單元”是掃描過程中確定和區分被掃對象的基本管理單位,它與缺陷的關閉與合并,權限管理,掃描中間結果的記錄等有關,直觀地理解就是一次源碼掃描過程中的被掃對象。
目前市面上的靜態應用安全測試工具都局限于處理單個掃描單元內部的污染數據傳播,無法處理跨掃描單元傳播的場景,隨著微服務/Serverless/FaaS等開發技術和模式的逐步演進,業務開發代碼日趨碎片化,使得這一問題愈發嚴重,成為靜態應用安全測試技術的重大挑戰。
跨掃描單元所關注的單元間依賴關系分為兩類:一類是通過引用二三方包而形成的依賴關系,另一類是通過各種遠程調用服務(remote procedure call , RPC)形成的依賴關系。前一類依賴關系通常在編譯時可以通過類似maven這樣的機制獲取,后一類依賴關系通常需要通過分析具體的配置文件獲取或者掃描時由用戶額外提供。
最直接的跨單元掃描解決方案是將所有相關掃描單元代碼進行合并掃描。但是在實際中,這樣會使得單次掃描的代碼量急劇膨脹而難以實現。另外,對于被依賴掃描單元來說,每次的重復掃描也將會是極大的資源浪費。
在實際中通常平均每個“應用”依賴的其他掃描單元(包括二三方包依賴和RPC依賴)超過200,最大甚至超過2000。對于這些依賴非常多的“應用”,所有相關掃描單元代碼合并后的代碼將會超過1000萬行。
本文所述分析工具當前運行節點的典型配置為8核32G內存,單個掃描任務要求掃描時間不超過10分鐘。工具的內存開銷與代碼行數基本成線性關系,實際中平均每10萬行代碼消耗內存約2G左右。時間開銷與代碼行數關系略高于O(n),10萬行代碼的掃描時間約1分鐘左右。因此合并掃描的方案在實際中由于空間、時間以及存儲成本的限制而無法實現。
一種更好的跨單元掃描解決方案是:首先,在不損失精度的前提下,以掃描單元為單位建立被依賴單元的靜態應用安全檢測中間結果表示,并將這些中間結果持久化地保存下來;其次,在其他單元掃描前,先依據其依賴關系將需要的中間結果下載到本地,并應用于當前單元的掃描過程。
根據上一節的討論,基于污染傳播和狀態機的中間結果表示核心即是函數摘要。另外,對于通常的RPC調用來說,只要在接口層面進行了統一,具體用何種語言實現對調用方是完全透明的,因此,基于函數摘要的跨單元掃描解決方案天然支持跨語言。上述方案如下圖所示:

經驗與體會
本文討論的Web應用安全靜態測試工具主要的使用方式是與應用持續集成/發布平臺對接,作為持續集成/發布的一個環節,在發布之前集成發布平臺調用工具進行代碼安全掃描,如果發現安全缺陷則通知用戶進行修復,修復后才可以發布上線。在這樣的應用場景下有如下幾點總結和體會:
- 實用的靜態應用安全測試工具通常是根據分析目標和應用場景在誤報、漏報、效率、易用性、可擴展性之間達到一個合理的平衡。
- Web應用安全風險和通用的內存安全漏洞有不同的特點,這些特點決定了分析算法和策略的選擇。
- 函數摘要對于Web應用安全風險相關的靜態分析來說是一種重要的技術,它不僅可以大大提高應用內掃描的效率,也是支持跨應用多語言掃描的一種方法。
- 靜態應用安全測試方法有許多天然的優點,但也有其固有的缺點,在實際中亟需將它與其他方法結合起來,才能更好地面對不斷涌現的Web應用安全檢測新場景和新需求。