编写你自己的 CodeQL 查询

CodeQL 提供了许多开箱即用的查询,特别是如果您使用 security-and-quality 查询套件。然而,CodeQL 的全部功能体现在您开始编写自己的查询时。当然,这并不简单。CodeQL 是一种复杂的查询语言,如果您查看 [GitHub 的 CodeQL 查询](https://github.com/github/codeql),会发现它们可能非常复杂。但如果您熟悉自己的编程语言,编写一些简单的查询应该是很容易的。

要编写 CodeQL 查询,您需要 Visual Studio Code (VS Code) 和 GitHub CodeQL 扩展([GitHub CodeQL 扩展](https://marketplace.visualstudio.com/items?itemName=GitHub.vscode-codeql))。

如果您已安装这两个工具,可以克隆启动工作区:

$ git clone --recursive https://github.com/github/vscode-codeql-starter.git

请注意 --recursive 参数!如果忘记此参数,您需要手动加载子模块:

$ git submodule update --remote

在 VSCode 中,选择 File | Open Workspace from File…​,并选择 vscode-codeql-starter.code-workspace 文件。

要从源代码创建数据库,您需要 CodeQL CLI。在 Mac 上,您可以使用 Homebrew 安装:

$ brew install codeql

对于其他平台,您可以从这里下载二进制文件:[CodeQL CLI Binaries](https://github.com/github/codeql-cli-binaries/releases/latest)。

将它们解压到一个文件夹并将路径添加到 $PATH 变量中(在 Windows 上是 %PATH%)。

接下来,进入您希望存储数据库的文件夹,并运行以下命令:

$ codeql database create <database name> \
  --language=<language> \
  --source-root=<path to source code>

这将为您仓库中的语言创建一个数据库。对于仓库中的所有语言,重复此步骤。

现在,在 VSCode 中打开 CodeQL 扩展,点击 Databases | From a folder。选择您在前一步中创建的数据库。您可以附加多个数据库并在它们之间切换(见图 14.26)。

image 2024 12 27 16 46 28 725
Figure 1. 图 14.26 – 将数据库附加到 VSCode CodeQL 扩展

您可以在启动工作区中找到所有支持语言的示例查询(codeql-custom-queries-<language>/example.ql)。查询通常包含一个带有元数据的注释头:

/**
 * @name Empty block
 * @kind problem
 * @problem.severity warning
 * @id javascript/example/empty-block
 */

接下来,它们导入所需的模块。模块名称通常与语言相关(例如 javascriptcsharpjava 等),但也可能是像 DataFlow::PathGraph 这样的名称:

import javascript

查询本身包含一个变量声明,一个可选的 where 块来限制结果,以及 select 语句:

from BlockStmt b
where
  b.getNumStmt() = 0
select b, "This is an empty block."

查看 GitHub 上的 CodeQL 示例,了解如何开始。你对语言的掌握程度越高,编写查询就越容易。以下查询将搜索 C# 中的空 catch 块:

import csharp
from CatchClause cc
where
  cc.getBlock().isEmpty()
select cc, "Poor error handling: empty catch block."

在 VSCode 中,你可以获得完整的 IntelliSense 支持(见图 14.27),这在编写查询时非常有帮助:

image 2024 12 27 16 48 05 234
Figure 2. 图 14.27 – VSCode 中的 IntelliSense

如果您从上下文菜单中运行查询(CodeQL: Run query),查询结果将显示在结果窗口中(见图 14.28)。

image 2024 12 27 16 48 56 175
Figure 3. 图 14.28 – CodeQL 查询结果

select 子句中的每个元素都有一个对应的列。你可以点击代码元素,VSCode 会在精确的位置打开相应的源文件。

关于 CodeQL,完全可以写一本书来详细讲解。这只是一个非常简短的介绍,但我认为通过自定义规则扩展代码扫描的能力是非常有价值的。有关更多信息,请参阅 CodeQL 文档和语言参考。