编写你自己的 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)。

您可以在启动工作区中找到所有支持语言的示例查询(codeql-custom-queries-<language>/example.ql
)。查询通常包含一个带有元数据的注释头:
/**
* @name Empty block
* @kind problem
* @problem.severity warning
* @id javascript/example/empty-block
*/
接下来,它们导入所需的模块。模块名称通常与语言相关(例如 javascript
、csharp
、java
等),但也可能是像 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),这在编写查询时非常有帮助:

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

select
子句中的每个元素都有一个对应的列。你可以点击代码元素,VSCode 会在精确的位置打开相应的源文件。
关于 CodeQL,完全可以写一本书来详细讲解。这只是一个非常简短的介绍,但我认为通过自定义规则扩展代码扫描的能力是非常有价值的。有关更多信息,请参阅 CodeQL 文档和语言参考。