代码分析平台CodeQL学习手记(十三)
导语:在本文中,我们将为读者详细介绍如何在命令行环境下构建CodeQL数据库。
在前面的文章中,我们为读者详细介绍了如何通过CodeQL平台的Visual Studio Code插件,即CodeQL for VS Code在本地编写和运行查询,并直接在工作区中展示查询结果,以及如何编写路径查询。在本文中,我们将为读者详细介绍如何在命令行环境下构建CodeQL数据库,并通过查询代码来分析它们。
CodeQL CLI简介
概述
在进行安全漏洞的变种分析的过程中,我们不仅可以通过CodeQL命令行接口(CLI)来创建所需的数据库,还可以直接从命令行或通过Visual Studio Code插件来查询这些数据库。
接下来,我们将为读者介绍如何安装和配置CodeQL CLI,一旦完成这些工作,我们就可以在命令行环境下执行CodeQL命令了。同时,我们还会介绍如何搭建相应的目录结构,以便CLI能够访问创建和分析数据库所需的工具、查询和库。
配置CodeQL CLI
通过适当的配置,我们可以让CodeQL CLI支持各种用例和目录结构。但是对于刚接触它的读者来说,我们建议采用简单一些的设置,具体如下所示。
对于使用Linux、Windows或10.14(“Mojave”)或更早版本的macOS操作系统的读者来说,只需按照以下步骤进行操作即可。但是,对于使用10.15(“Catalina”)版本的macOS操作系统的读者来说,步骤1和步骤4会略有不同,具体情况将在下文中进行详述。
1. 下载CodeQL CLI 的zip安装包
CodeQL CLI的安装包是一个zip压缩包,其中含有安装CodeQL所需的各种工具、脚本和文件。对于使用Linux、Windows或10.14(“Mojave”)或更早版本的macOS平台的读者来说,可以通过https://github.com/github/codeql-cli-binaries/releases下载相应的安装包。对于使用10.15(“Catalina”)版本的macOS操作系统的读者来说,则需要确保所用Web浏览器不会自动提取zip文件。如果当前使用的是Safari浏览器,请在下载CodeQL CLI安装包之前执行以下步骤:
· 启动Safari浏览器。
· 从Safari浏览器的菜单中,选择“Preferences…”。
· 单击“General”选项卡。
· 确保“Open “safe” files after downloading”复选框处于未选中状态。
2. 新建CodeQL目录
之后,我们需要新建一个目录,该目录用于存放CLI以及使用的查询和库。本文中,我们假设该目录为$HOME/codeql-home。
实际上,由于CLI的内置搜索操作会自动在其所有同级目录中查找用于数据库创建和分析的相关文件,因此,如果将这些组件存放在它们自己的目录中的话,不仅可以防止CLI搜索不相关的同级目录,同时,还能确保所有文件都处于拿来就用的状态,这样的话,就无需在命令行上指定任何其他选项了。
3. 获取CodeQL查询的本地副本
我们可以从GitHub中签出CodeQL存储库的副本,地址为https://github.com/Semmle/ql。这个存储库中含有利用CodeQL处理C/C++、C#、Java、JavaScript/Typescript和Python代码所需的各种查询和库。
此外,由于用于分析Go代码的CodeQL库和查询位于CodeQL for Go存储库中,具体地址为https://github.com/github/codeql-go/,所以,我们可以将这个存储库的副本签入到主CodeQL repo的同级目录中。举例来说,如果我们的CodeQL存储库副本的路径是$HOME/codeql-home/codeql-repo,那么,我们就可以将Go存储库的CodeQL提取到$HOME/codeql-home/codeql-go-repo中。
在这些存储库中,查询和库都是以QL包的形式存在的。实际上,除了查询本身之外,QL包中还含有许多重要的元数据,这些元数据是用于告诉CodeQL CLI如何处理查询文件的。 有关更多信息,请参见https://help.semmle.com/codeql/codeql-cli/reference/qlpack-overview.html。
需要注意的是,不同的用户需要选择不同版本的CodeQL查询,大家可以根据自己的情况选择合适的版本:
· 对于希望使用最新的CodeQL查询的用户来说,请选择主分支。如果您使用的是最新版本的CLI,请使用该版本的查询。同时,每次升级到CLI的新版本时,请及时更新查询。
· 对于特定LGTM企业版本中使用的查询,请使用标记有相关版本号的分支。例如,标记为V1.23.0的分支对应于LGTM Enterprise 1.23。如果要将数据上传到LGTM企业版,请使用该版本。
4. 解压缩zip存档
对于Linux、Windows和macOS(10.14“Mojave”及更早版本)用户来说,只需将zip文件解压到步骤2中所创建的目录中即可。
例如,如果代码库副本的路径是$HOME/codeql-home/codeql-repo,那么请将CLI提取到$HOME/codeql-home/codeql-cli中。对于使用macOs的“Catalina”版本的用户,则需要在终端运行以下命令(其中${install_loc}表示在步骤2中创建的目录):
(1)mv ~/Downloads/codeql*.zip ${install_loc}
(2)cd ${install_loc}
(3)xattr -c codeql*.zip
(4)unzip codeql*.zip
5. 运行CodeQL
完成解压后,可以通过以下几种方式运行CodeQL可执行文件,从而启动CodeQL进程:
· 执行
· 将
完成上述工作后,我们就可以执行CodeQL命令了。有关CodeQL CLI命令的完整介绍,请参阅https://help.semmle.com/codeql/codeql-cli/commands.html。
请注意,将codeql添加到PATH变量后,就可以通过CodeQL for Visual Studio Code插件访问该命令行接口以编译和运行查询了。
6. 检查CodeQL CLI是否安装成功
我们可以通过执行CodeQL CLI提供的各种子命令,来验证是否为创建和分析数据库做好了准备:
· 运行codeql resolve languages命令以显示可以为哪些语言创建数据库。该命令会列出CodeQL CLI包中默认支持的语言。
· 运行codeql resolve qlpacks命令以显示CLI可以找到哪些QL包。该命令将显示包含在CodeQL存储库中的QL包的名称,例如:codeql-cpp、codeql-csharp、codeql-go、codeql-java、codeql-javascript和codeql-python。除此之外,CodeQL存储库还包含一些“upgrade”包和“legacy”包。当您想要升级数据库时,CLI就会用到升级包,以便可以使用比创建数据库时使用的更新的版本的CodeQL工具链对其进行分析。遗留包的作用是,确保使用旧产品创建的自定义查询和库与当前的CodeQL版本保持兼容。
创建CodeQL数据库
概述
在使用CodeQL分析代码的时候,需要先从代码中提取关系数据,并通过这些关系数据来构建CodeQL数据库。简单来说,这里所说的数据库实际上就是一个目录,其中保存的是利用查询分析代码所需的各种数据。接下来,我们将会为读者说明如何使用database create子命令来创建CodeQL数据库。
先决条件
在生成CodeQL数据库之前,需要做好下列准备:
· 安装并配置好CodeQL CLI,具体见上文。
· 签出要分析的代码库的版本。该目录应该已为构建做好了相应的准备,并已安装所有依赖项。
执行codeql database create命令
通过从项目的签出根目录运行以下命令来创建CodeQL数据库:
codeql database create
其中,我们必须指定:
· --language:为其创建数据库的语言的标识符。CodeQL支持为以下语言创建数据库:
根据源文件的位置和待分析的语言的不同,可能还需指定其他选项:
--source-root:用于创建数据库的源文件的根目录。在默认情况下,命令会将当前目录视为源文件的根目录,所以,我们可以通过该选项指定其他位置。
--command:仅适用于编译型语言,通常用于调用编译器的构建命令。注意,请不要为Python和JavaScript语言指定--command选项,因为命令通常会在当前文件夹下面运行,但是,如果指定了--source-root选项,则会从指定的文件夹运行。如果没有使用—command选项的话,CodeQL将使用内置的AutoBuilder自动检测构建系统。
有关创建数据库时的所有选项的详细信息,请参阅https://help.semmle.com/codeql/codeql-cli/commands/database-create.html。
有关运行database create子命令为各种编译型和非编译型语言创建数据库的更多信息,请参见https://help.semmle.com/codeql/codeql-cli/procedures/databases-examples.html。
进展与结果
如果我们指定的选项出现问题,系统将报告相应的错误信息。对于解释型语言来说,提取进度将显示在控制台中——对于每个源文件,它都会报告提取的成败情况。对于编译型语言,控制台将显示构建系统的输出信息。
成功创建数据库后,我们就能在命令中指定的路径处看到一个新目录。这个目录含有许多子目录,其中存放的是(分析所需的)关系数据以及源文件的归档,即创建数据库时所用的源文件的副本,它将用于显示分析结果。
从LGTM.com获取数据库
实际上,LGTM.com网站已经借助CodeQL平台分析了数以千计的开源项目。对于LGTM.com上的每个项目,我们都可以下下载一个归档的CodeQL数据库,该数据库对应于最新的代码修订版本。此外,我们还可以使用CodeQL CLI来分析这些数据库。
从LGTM.com下载数据库:
· 登录LGTM.com。
· 找到自己感兴趣的项目,并打开Integrations选项卡(例如,Apache Kafka)。
· 滚动到页面底部的CodeQL databases for local analysis部分。
· 下载要分析的语言的数据库。
· 解压数据库。
在进行分析之前,请尝试升级解压的数据库,以确保它们与CodeQL查询和库的本地副本相兼容。
需要注意的是,在创建数据库时,CodeQL CLI不会从其他配置文件(例如C#中的web.xml文件以及Java中的.properties文件)提取数据。这意味着使用CodeQL CLI创建的CodeQL数据库可能与从LGTM.com获得的或使用遗留的QL命令行工具创建的数据库有所不同。 因此,从CodeQL CLI创建的数据库生成的分析结果可能不同于从其他地方获得的数据库生成的分析结果。
示例:创建CodeQL数据库
非编译型语言
CodeQL CLI为我们提供了为非编译型语言创建数据库的提取器——特别是JavaScript、TypeScript和Python语言。当我们创建数据库时,如果通过--Language选项指定了JavaScript或Python语言,就会自动调用这些提取器。在为这些语言创建数据库时,必须确保所有其他依赖项都已经准备妥当。
需要注意的是,当我们使用database create命令为JavaScript和Python语言创建数据库时,一定不要使用--command选项。否则的话,将会覆盖正常的提取器调用,从而导致创建的是一个空数据库。
为JavaScript与TypeScript代码创建数据库
为JavaScript创建数据库时,虽然不需要额外的依赖项,但是,如果项目中含有TypeScript文件的时候,则必须安装6.x或更高版本的Node.js。在命令行中,可以通过--language=javascript选项来提取JavaScript和TypeScript文件:
codeql database create --language=javascript --source-root
其中,我们通过--source-root选项指定了一个路径,即创建数据库的位置,但未必是代码库的签出根目录。
为Python代码创建数据库
为Python代码创建数据库时,必须确保:
· 已经安装了所有必需的Python版本。
· 可以访问pip,并且可以安装代码库所依赖的任何包。
· 已经安装了packaging(https://pypi.org/project/packaging/)和virtualenv(https://pypi.org/project/virtualenv/)模块。
在命令行中,必须指定--language=python选项:
codeql database create --language=python
从代码的签出根目录执行database create子命令后,就会在
编译型语言
对于编译型语言来说,生成数据库时CodeQL需要调用所需的构建系统,因此,必须确保CLI可以调用构建方法。
检测构建系统
实际上,CodeQL CLI已经提供了用于分析C/C++、C#、Go和Java代码的autobuilder。在使用CodeQL autobuilder时,无需指定任何构建命令即可构建编译型语言项目——当autobuilder被调用时,CodeQL平台会为构建系统查找源代码,并尝试运行提取数据库所需的最优命令集。
执行codeql database create命令时,如果使用—language选项指定了某种编译型语言,系统就会自动调用autobuilder,这时,根本无需使用--command选项。例如,对于Java代码库来说,我们只需运行如下所示的命令:
codeql database create --language==java
当代码库使用标准构建系统的时候,创建数据库最简单的方法就是使用autobuilder。对于需要非标准构建步骤的源代码,则需要在命令行中显式定义各个步骤。
为Go代码创建数据库
对于Go语言来说,我们应该始终使用CodeQL AutoBuilder。为此,需要安装Go toolchain(版本应该在1.11或更高版本以上),如果存在依赖项,则还需安装适当的依赖项管理器,例如dep(地址为https://golang.github.io/dep/),或Glide(地址为http://glide.sh/)。
此外,不要指定任何构建命令,因为这样做会覆盖autobuilder调用,导致创建的是一个空数据库。
指定构建命令
下面的示例旨在让您了解如何为编译型语言指定构建命令。需要注意的是,--command选项后面只能跟单个参数,但是,如果需要使用多个命令的话,该怎么办呢?很简单,可以使用多个--command选项。
如果需要传递多个子命令和选项,则需要用括号将其括起来。
· 使用make命令构建C/C++项目:
codeql database create cpp-database --language=cpp --command=make
· 使用dotnet build(适用于.NET Core 3.0或更高版本)构建C#项目:
codeql database create csharp-database --language=csharp --command='dotnet build /t:rebuild'
在Linux和macOS(但不包括Windows)系统上,使用.NET Core2或更早版本来构建C#项目时,需要禁用共享编译功能,因此需要使用下列命令:
codeql database create csharp-database --language=csharp --command='dotnet build /p:UseSharedCompilation=false /t:rebuild'
· 使用Gradle构建Java项目:
codeql database create java-database --language=java --command='gradle clean test'
· 使用Maven构建Java项目:
codeql database create java-database --language=java --command='mvn clean install'
· 使用Ant构建Java项目:
codeql database create java-database --language=java --command='ant -f build.xml'
· 使用自定义构建脚本构建项目:
codeql database create new-database --language=
上面的命令将运行一个自定义脚本,该脚本中含有构建项目所需的所有命令。
小结
在本文中,我们将为读者详细介绍如何在命令行环境下构建CodeQL数据库,在后面的文章中,我们将为读者详细介绍如何通过查询代码来分析这些数据库。
备注:本系列文章乃本人在学习CodeQL平台过程中所做的笔记,希望能够对大家有点滴帮助——若果真如此的话,本人将备感荣幸。
参考资料:https://help.semmle.com/
发表评论