記事ディレクトリ
序文
Java コード監査に CodeQL を使用する方法を学びます。いくつかの概念と例が含まれています。
CodeQLの基本構文
CodeQL は解析エンジンを使用して、データベースに監査する必要があるプロジェクトを解析します。ここでのデータベースは、CodeQL が認識できる中間層データベースに変換されることに注意してください。コア解析エンジンはオープンソースではないため、中間データベースが生成されます。次に、関連する QL ルールを記述すると、CodeQL エンジンがルールに従ってデータベース内の条件を満たすデータを検索し、分析できるようになります。
1. 文法構造
1) QL クエリの構文構造は次のとおりです。
from [datatype] var /* ... 变量声明... */
where condition(var = something) /* ... 逻辑公式 ... */
select var /* ... 表达式 ... */
2) 簡単な例では、i==1 の場合にすべての整数 i のうち i を出力します。
// 表示我们要引入CodeQL的类库,因为我们分析的项目是java的,所以在ql语句里,必不可少
import java
// 表示我们定义一个变量i,它的类型是int,表示我们获取所有的int类型的数据
from int i
// 表示当i等于1的时候,符合条件
where i = 1
// 表示输出i
select i
3) 公式プラットフォームを使用して、ルールの作成を練習することもできます。LGTM クエリ コンソール: https://lgtm.com/query
2. クラスライブラリ
1) CodeQL 解析エンジンは、監査する必要があるプロジェクト コードを、CodeQL で認識できる AST データベースに変換します。形式は次のとおりです。一般に 2 つのレベルがあり、1 つはインポートされたパッケージ、もう 1 つはクラスであることがわかります。クラスの下にはメソッドやプロパティなどがいくつかあります。クラスライブラリは実際には上記のASTの対応関係です。
2) たとえば、すべてのクラスのメソッドを取得したい場合、AST のメソッドとは、現在のプロジェクトのすべてのメソッドを取得することを意味します。次のように:
import java
from Method method
select method
3) それをアップグレードし、Method クラスに組み込まれたいくつかのメソッドを通じて結果をフィルタリングします。たとえば、get という名前のメソッド名を取得します。
import java
from Method method
where method.hasName("get")
/**
method.getName() 获取的是当前方法的名称
method.getDeclaringType() 获取的是当前方法所属class的名称。
**/
select method.getName(), method.getDeclaringType()
3. 述語
1) 述語は、QL プログラムを構成する論理関係を記述するために使用されます。概念的には関数に似ています。個人的には、述語は 1 要素配列か 2 要素配列であると公式ドキュメントから理解していますが、1 要素配列の集合述語アリティは 1、2 要素配列の集合述語アリティは 2 です。通常、述語内のすべてのタプルには同じ数の要素があります。述語の数は、考えられる結果変数を除いた要素の数です。QL には多くの組み込み述語があります。公式ドキュメントを参照してください: https://codeql.github.com/docs/ql- language-reference/ql- language-specation/#built-ins。
2) 述語条件を定義します。
- キーワード述語が必要です
- 小文字で始まる識別子が必要です。例: is Country
- パラメータを定義し、複数のパラメータをカンマで接続します。パラメータごとに、パラメータのタイプとパラメータ変数の識別子を指定する必要があります。
- 述語自体は大きな中括弧「{ }」で囲まれています。
3) 公式例:
predicate isCountry(string country) {
country = "Germany"
or
country = "Belgium"
or
country = "France"
}
predicate hasCapital(string country, string capital) {
country = "Belgium" and capital = "Brussels"
or
country = "Germany" and capital = "Berlin"
or
country = "France" and capital = "Paris"
}
4) 上記の get クエリの例は、次のように書き換えることもできます。
import java
predicate isGet(Method method) {
exists(|method.hasName("get"))
}
from Method method
where isGet(method)
select method.getName(), method.getDeclaringType()
语法解释:
predicate 表示当前方法没有返回值。
exists子查询,是CodeQL谓词语法里非常常见的语法结构,它根据内部的子查询返回true or false,
来决定筛选出哪些数据。
5) 述語は、結果のある述語と結果のない述語に分けることができます。違いは特殊変数 result が導入されているかどうかで、result がある場合は述語を置き換えることができます。公式ケースを参照してください:
// 无结果的谓词
predicate isSmall(int i) {
i in [1 .. 9]
}
// 如果i是正整数并且小于10,则isSmall(i)成立。
// 有结果的谓词
int getSuccessor(int i) {
result = i + 1 and
i in [1 .. 9]
}
// 如果i是正整数并且小于10,则这个谓词的结果就是接替i
4. 基本データ型とその組み込み関数
1) QL 言語の基本的なデータ型 (整数、浮動小数点、日付、ブール型、文字列型など)。QL 言語では、サポートされるすべてのデータ型に対応する組み込み関数があることに注意してください。平たく言えば、システムが作成した関数は述語であり、それらを直接使用できます。
2) たとえば、整数の絶対値を見つけたい場合は、1.abs() などの組み込み関数 abs() を直接呼び出すことができます。
2) 特定のタイプの変数を呼び出したい場合、一般的な形式は次のとおりです。変数の後にピリオドを直接追加し、呼び出す組み込み関数を追加します。同時に、複数の関数をドットで直列につなぐ、つまり変数に対して複数の処理を連続して行うこともでき、例えば整数変数sの場合、絶対値を求めてから平方根をとるというような表現もできます。この処理プロセス: s.abs().sqrt()。
3) 他の言語と同様の文字列型。
from string s
where s = "he\"llo"
select s
4) 整数型と浮動小数点型。
from float a, int b
where a = 5.3 and b = 2
// pow的作用就是参数的几次幂 下方例子就是5.3的2次幂
select a.pow(b)
5) 日付タイプ。最初の武漢の流行から経過した日数を計算するクエリを作成します。
from date start, date now
// toDate()作用就是将指定的字符串转换为日期值
where start = "1/12/2019".toDate() and now = "25/10/2022".toDate()
select start.daysTo(now)