在CodeQL CLI中使用自定義查詢
為了使用CodeQL進行定制分析,我們可以通過自己編寫查詢來實現查找漏洞或錯誤。CodeQL的查詢類型有:
- 告警查詢:突出顯示代碼中特定位置的問題的查詢。
- 路徑查詢:代碼中source和sink之間信息流的查詢。
基本查詢結構
用CodeQL編寫的查詢文件擴展名為.ql
,並包含一個select
子句。許多現有查詢都包含其他可選信息,並具有以下結構:
/** * * Query metadata * */ import /* ... CodeQL libraries or modules ... */ /* ... Optional, define CodeQL classes and predicates ... */ from /* ... variable declarations ... */ where /* ... logical formula ... */ select /* ... expressions ... */
import語句
每個查詢通常包含一個或多個import
語句,這些語句定義了要導入到查詢中的庫或模塊。庫和模塊提供了一種將相關類型,謂詞(用於描述組成QL程序的邏輯關系)和其他模塊組合在一起的方法。然后,查詢可以訪問您導入的每個庫或模塊的內容。
From子句
該from
子句聲明查詢中使用的變量。每個聲明必須采用 <type> <variable name>
的形式。
Where子句
該where
子句定義了適用於該from
子句中聲明的變量以生成結果的邏輯條件。該子句使用聚合,謂詞和邏輯公式將目標變量限制為較小的集合,這些集合滿足已定義的條件。
Select 子句
該select
子句指定要顯示的變量,這些變量需符合where
子句中定義的條件。select子句的有效結構由元數據中指定的@kind
屬性定義。
告警查詢(@kind problem
)的Select子句由兩“列”組成,其結構如下:
select element, string element:查詢標識的代碼元素,用於定義顯示告警的位置。 string:一條消息,其中還可以包含鏈接和占位符,說明生成告警的原因。
select
語句最后一欄中定義的告警消息,使用有關鏈接或占位符,提供通過查詢所找到的告警或路徑的更多詳細信息。
編寫查詢元數據
每個查詢文件都是以查詢元數據作為開始,它為用戶提供有關查詢的信息,並告訴CodeQL CLI如何處理查詢結果。
我們在使用database analyze
命令進行查詢時,必須包括以下兩個屬性,以確保得到正確的查詢結果:
- 查詢標識符(
@id
):是一串小寫字母或數字,通過/
或-
分隔構成的單詞序列,用於識別和分類查詢。
- 查詢類型(
@kind
):標識查詢是告警(@kind problem
)還是路徑(@kind path-problem
)。
元數據屬性
所有查詢文件都支持以下屬性:
屬性 | 值 | 描述 |
---|---|---|
@description |
<text> |
用一段簡單的話描述查詢的目的以及查詢結果的重要性。該描述以純文本編寫,並使用單引號(' )將代碼括起來。 |
@id |
<text> |
是一串小寫字母或數字,通過/ 或- 分隔構成的單詞序列,用於識別和分類查詢。每個查詢必須具有唯一的 ID。為確保這一點,對每個ID使用固定的結構可能會有所幫助。例如,標准LGTM查詢具有以下格式:<language>/<brief-description> 。 |
@kind |
|
標識查詢是告警(@kind problem )還是路徑(@kind path-problem )。有關這些查詢類型的更多信息,請參見關於CodeQL查詢。 |
@name |
<text> |
定義查詢標簽的語句。該名稱以純文本形式編寫,並使用單引號(' )將代碼括起來。 |
@tags |
|
這些標簽將查詢按大類分組在一起,以使其更易於搜索和識別。除了此處列出的常用標簽外,還有許多更具體的類別。有關更多信息,請參閱《 查詢元數據樣式指南》。 |
@precision |
|
表示查詢結果為“真肯定”(相對於“假肯定”結果)的百分比。這與@problem.severity 屬性一起確定默認情況下是否在LGTM上顯示結果。 |
@problem.severity |
|
定義查詢生成的任何警報的嚴重性級別。這與@precision 屬性一起確定默認情況下是否在LGTM上顯示結果。 |
對於過濾器查詢的其他屬性
過濾器查詢用於定義其他約束,以限制其他查詢返回的結果。篩選器查詢必須具有與@kind
要篩選其結果的查詢相同的屬性。不需要其他元數據屬性。
例子
一個標准的Java查詢元數據:
有關查詢元數據的更多示例,請參見GitHub存儲庫中的標准CodeQL查詢。
定義查詢結果
您可以通過修改查詢的select
語句來控制分析結果在源代碼中的顯示方式。
概述
告警查詢必須在元數據中定義@kind problem屬性。有關更多信息,請參見CodeQL查詢的元數據。select
語句最基本的形式必須包含兩“列”:
- Element ——查詢所標識的代碼元素。這定義了告警的位置。
- String——為該代碼元素顯示的消息,描述了生成告警的原因。
編寫一個select語句
我們以一個使用標准CodeQL CodeDuplication.qll
庫識別相似文件的簡單查詢作為示例。
基本select語句
import java import external.CodeDuplication from File f, File other, int percent where similarFiles(f, other, percent) select f, "This file is similar to another file."
這個基本的select語句有兩列:
- 顯示告警的元素:
f
對應於File
。 - 要顯示的字符串消息:
"This file is similar to another file."
包含相似文件的名稱
select語句定義的告警信息是固定的,不能給用戶提供太多信息。由於查詢識別出了相似文件(other
),因此很容易擴展select
語句以告知用戶這些相似文件的名稱。例如:
select f, "This file is similar to " + other.getBaseName()
- Element :
和之前一樣為f
。 - String:"This file is similar to "—字符串文本與相似文件的文件名通過getBaseName()拼接在一起
。
盡管這比原始的select語句提供了更多信息,但用戶仍然需要手動查找其他文件。
添加鏈接到相似文件
您可以在告警信息中使用占位符以插入其他信息,例如,指向相似文件的鏈接。占位符使用$@定義
,並使用select語句的后兩列中的信息來填充。例如,下述select語句就返回了4列信息:
select f, "This file is similar to $@.", other, other.getBaseName()
- Element:
和之前一樣為f
。 - 字符串消息:"This file is similar to $@."——該字符串包含一個占位符,它將顯示接下來兩列的合並內容。
- 占位符元素:
other
對應於相似文件。 - 占位符的字符串文本:
other.getBaseName()所返回的短文件名
。
顯示告警消息時,$@
占位符將替換為根據該select
語句定義的第三第四列內容創建的鏈接。
如果使用$@
在說明信息中多次使用占位符標記,則第N
個使用的$@
將由2N+2列
和2N+3
列組成的鏈接代替。如果附加列數量多於占位符標記,則末尾的列將被忽略。相反,如果附加列數量少於占位符標記,則末尾的$@
標記將被視為普通文本,而不是占位符。
增加文件相似程度的一些細節
我們可以更進一步,更改select
語句以報告兩個文件中相似的內容部分,因為這部分信息已經在查詢中可用。例如:
select f, percent + "% of the lines in " + f.getBaseName() + " are similar to lines in $@.", other, other.getBaseName()
由於此處添加的新元素不需要是可單擊的,因此我們可以將它們直接拼接到字符串信息中。
創建一個自定義的QL包
我們編寫的查詢應該保存在自定義QL包文件夾或其子目錄中。QL包用來整理在分析時使用的文件,包括查詢、庫文件、查詢套件和重要的元數據。QL包目錄的根目錄下必須包含一個以qlpack.yml
命名的文件,該文件包含name、version以及libraryPathDependencies字段屬性。如果這個包還包含查詢套件,可以使用suites這個字段來指定其位置。
執行命令的時候,codeql會掃描其安裝目錄或者子目錄查找qlpack.yml文件,文件中的元數據會告知codeql如何編譯查詢、依賴什么庫以及查詢套件所在的位置。
例如一個自定義C++查詢和庫的QL包的qlpack.yml文件可能包含以下內容:
name: my-custom-queries version: 0.0.0 libraryPathDependencies: codeql-cpp suites: my-custom-suites
其中codeql-cpp是codeql倉庫中用於C/C++分析的QL包的名稱。
QL包包含的其它內容(codeql分析時使用的查詢和庫文件)與qlpack.yml放在同一個目錄,或者它的子目錄中。
例如,一個包含如下文件目錄的QL包,如果需要導入CustomSinks.qll只需要在包的任意目錄聲明:
import mycompany.java.CustomSinks
qlpack.yml mycompany/ java/ security/ CustomSinks.qll Security/ CustomQuery.ql
我們可以通過如下方式使用自定義的查詢:
codeql database analyze xssdb E:\codeql\codeql-repo\customql\java\xss.ql --format=sarif-latest --output=result.sarif
codeql database analyze xssdb E:\codeql\codeql-repo\customql\java\xss.ql --format=csv --output=codeql.csv