一、CodeQL 工作流程
CodeQL 的整體工作流程如下圖所示:
(圖片來源:https://blog.semmle.com/introduction-to-variant-analysis-part-2/)
CodeQL 的整體思路是把源代碼轉化成一個可查詢的數據庫,通過 Extractor 模塊對源代碼工程進行關鍵信息分析提取,構成一個關系型數據庫。CodeQL 的數據庫並沒有使用現有的數據庫技術,而是一套基於文件的自己的實現。
對於編譯型語言,Extractor 會監控編譯過程,編譯器每處理一個源代碼文件,它都會收集源代碼的相關信息,如:語法信息(AST 抽象語法樹)、語意信息(名稱綁定、類型信息、運算操作等),控制流、數據流等,同時也會復制一份源代碼文件。而對於解釋性語言,Extractor 則直接分析源代碼,得到類似的相關信息。
關鍵信息提取完成后,所有分析所需的數據都會導入一個文件夾,這個就是 CodeQL database, 其中包括了源代碼文件、關系數據、語言相關的 database schema(schema 定義了數據之間的相互關系)。
接下來就可以對數據庫進行查詢了,CodeQL 自己定義實現了一套名為 QL 的查詢語言,並提供了相應的支持庫和運行環境。
最終將查詢結果展示給用戶,方便用戶進行進一步的人工審計分析。
二、CodeQL CLI 安裝和配置
1.下載CodeQL CLI 壓縮包
https://github.com/github/codeql-cli-binaries/releases
2.創建CodeQL目錄,如$HOME/codeql-home
3.創建CodeQL查詢的本地拷貝
CodeQL倉庫包含分析C/C++, C#, Java, JavaScript、python等所需的查詢和庫文件。需要拷貝一份倉庫到codeql-home目錄,重命名倉庫文件夾為codeql-repo
倉庫下載地址:https://github.com/github/codeql
- go的倉庫地址:https://github.com/github/codeql-go/
- 假設CodeQL倉庫目錄為$HOME/codeql-home/codeql-repo,那么go的倉庫目錄可以設置為$HOME/codeql-home/codeql-go
4.解壓CodeQL CLI 壓縮包$HOME/codeql-home目錄
5.運行CodeQL
(1)通過直接執行$HOME/codeql-home/codeql/codeql來運行CodeQL
(2)將$HOME/codeql-home/codeql目錄添加到環境變量
三、創建CodeQL數據庫
命令:
codeql database create <database> --language=<language-identifier>
參數說明:
<database>:創建的數據庫的路徑,必須是不存在的文件夾
--language:如下
C/C++ | cpp |
C# | csharp |
Go | go |
Java | java |
JavaScript/TypeScript | javascript |
Python | python |
其它參數:
--source-root 指定數據庫創建時的源文件根目錄,默認為當前目錄。
--command 指定語言的編譯命令,不要給python和JavaScript指定該命令。
非編譯型語言創建數據庫
codeql database create --language=javascript --source-root <folder-to-extract> <output-folder>/javascript-database
四、使用CodeQL CLI分析數據庫
命令:
codeql database analyze <database> <queries> --format=<format> --output=<output>
參數說明:
<database> 預分析的數據庫路徑
<queries> 要在數據庫上運行的查詢。可以指定一個或多個單獨的查詢文件,指定將以遞歸方式搜索查詢文件的目錄,或者命名定義了一組特定查詢的查詢套件。
--format 分析生成的結果文件的文件格式
--output 分析結果的輸出路徑
還可以通過--threads
指定運行查詢時要使用的線程數。默認選項是1
示例:
codeql database analyze <javascript-database> ../ql/javascript/ql/src/Declarations/UnusedVariable.ql --format=csv --output=js-analysis/js-results.csv
上述分析的結果會在新創建的文件夾
js-analysis
下的js-results.csv文件中輸出
運行目錄中的所有查詢
我們可以通過提供目錄路徑來運行目錄中的所有查詢,而沒必要列出目錄中的所有單個查詢文件。由於是通過遞歸搜索讀取查詢文件的,因此子文件夾中包含的所有查詢也將被執行。
重要
您不應在執行
database analyze
時指定QL pack的根目錄, 因為它包含一些並非為命令使用而設計的特殊查詢。如果要運行更多的有用的查詢,請選擇LGTM.com查詢套件之一。
例如,要執行Functions
目錄中包含的所有Python查詢,您將運行:
codeql database analyze <python-database> ../ql/python/ql/src/Functions/ --format=sarif-latest --output=python-analysis/python-results.sarif
會生成一個SARIF結果文件。通過--format=sarif-latest
可確保結果根據CodeQL支持的最新SARIF規范進行格式化。
結果
您可以將分析結果保存為多種不同格式,包括SARIF和CSV。
SARIF(數據分析結果交換格式)是定義輸出文件格式的OASIS 標准。 SARIF 標准用於簡化靜態分析工具分享其結果的方式。 有關更多信息,請參見SARIF概述。
如果將分析結果輸出到CSV文件,則輸出的每條告警將包含以下信息:
名稱 | 標識結果的查詢名稱。 | Inefficient regular expression |
描述 | 查詢的描述。 | A regular expression that requires exponential time to match certain inputs can be a performance bottleneck, and may be vulnerable to denial-of-service attacks. |
嚴重程度 | 查詢的嚴重性。 | error |
信息 | 告警消息。 | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '\\\\'. |
路徑 | 包含告警的文件的路徑。 | /vendor/codemirror/markdown.js |
起始行 | 觸發告警的代碼開始的文件行。 | 617 |
開始列 | 起始行的列,用於標記告警代碼的開始。第一列不包括在內。 | 32 |
結束行 | 觸發告警的代碼結束的文件行。與起始行相同時不包括在內。 | 64 |
結束列 | 可能的話,在結束行的列中標記告警代碼的結尾。否則,將重復結束行。 | 617 |
結果文件可以集成到您自己的代碼審查或調試設施中。例如,借助IDE的SARIF文件查看插件查看輸出的SARIF文件時,可以讓告警在源代碼中突出顯示。