代码分析平台CodeQL学习手记(十四)
导语:在本文中,我们继续为读者介绍如何在命令行环境下通过查询代码来分析这些数据库、自定义查询以及更新数据库。
在前面的文章中,我们为读者详细介绍了如何在命令行环境下构建CodeQL数据库,在本文中,我们继续为读者介绍如何在命令行环境下通过查询代码来分析这些数据库、自定义查询以及更新数据库。
使用 CodeQL CLI 分析数据库
概览
实际上,利用CodeQL平台分析代码的过程,就是在从代码中提取的数据库上运行查询的过程。所以,接下来我们将向大家展示如何使用database analyze子命令来分析数据库,从而生成可以在源代码中显示为警报或路径的解释型结果。关于如何使用database analyze命令编写查询的方法,将在后面详细介绍。
运行查询的其他命令
使用database analyze运行查询的时候,对于元数据是具有非常严格的要求的。实际上,除了使用这条命令之外,我们还可以使用管道级子命令来执行查询代码,具体如下所示:
· database run-queries命令,该命令将以中间二进制格式(通常成为BQRS 格式)输出非解释型结果。
· query run命令,该命令既可以输出 BQRS 格式的文件,也可以直接将结果表输出至命令行,并且,直接在命令行中查看结果对于使用CLI进行迭代查询开发来说是非常有帮助的。
使用这两个命令运行查询时,对于元数据的要求就没有像database analyze命令那样严格了。 但是,要想保存人类可读的数据,则必须使用bqrs decode plumbing子命令来处理所有BQRS 文件。因此,在大多数情况下,最简单的方法就是使用database analyze命令来直接生成解释型结果。
先决条件
在开始分析之前,您必须做好下列准备工作:
1. 安装并配置好CodeQL CLI,使其能够查找位于CodeQL存储库中的查询和库。
2. 为要分析的源代码创建一个CodeQL数据库。
运行codeql database analyze命令
当我们运行database analyze命令时,它会完成如下所示的工作:
1. 运行一个或多个查询文件,也就是在CodeQL数据库上运行相应的查询代码。
2. 根据某些查询元数据来解释结果,以便在源代码中的相应位置处显示警示信息。
我们可以通过运行如下所示的命令来分析数据库:
codeql database analyze
其中,我们必须指定下列内容:
· --format:分析过程中生成的结果文件的格式。这里可以使用多种格式,例如CSV、SARIF和图格式,等等,详情请参阅https://help.semmle.com/codeql/codeql-cli/commands/database-analyze.html。
· --output:分析过程中生成的结果文件的输出路径。
至于在分析数据库时可以使用的所有选项的详细信息,请参阅https://help.semmle.com/codeql/codeql-cli/commands/database-analyze.html。
示例
对于下面的示例,我们将假设已经在一个目录中创建了CodeQL数据库,并且该目录为CodeQL和CodeQL for Go存储库的本地副本的同级目录。
运行单个查询
要在JavaScript代码库上运行单个查询,可以从数据库所在的目录中运行如下所示的命令:
codeql database analyze
这个命令将运行一个简单的查询,查找与从未用过的变量、导入语句、函数或类相关的潜在安全漏洞——这是CodeQL存储库中提供的一个JavaScript查询。当然,我们也可以运行多个查询,为此,只需提供一个以空格分隔的路径列表即可。
上述分析过程将在新目录(即js-analysis)中生成一个CSV文件(即js-results.csv)。
此外,我们还可以使用database analyze命令来运行自定义的查询,详情会在后文中加以介绍。
运行LGTM.com查询套件
实际上,CodeQL存储库还为我们提供了许多查询套件,这些套件可以作为更广泛的代码审查的一部分,来处理我们的目标代码。CodeQL查询套件都是以.qls文件的形式保存的,其中含有某些必要的指令,使其可以根据特定的元数据属性来选择要运行的查询。
此外,CodeQL存储库中提供的查询套件,通常会选择LGTM.com默认运行的查询。之所以选择这些查询,就是为了突出显示与每种语言最相关和最有用的结果。
用于特定语言的LGTM查询套件位于CodeQL存储库中的以下路径中:
ql/
以及CodeQL for Go存储库中的以下路径中:
ql/go/src/codeql-suites/go-lgtm.qls
实际上,这些位置都是由标准QL包中的元数据所规定的。这意味着CodeQL知道从哪里可以找到相应的套件文件,所以,我们根本无需在命令行中指定完整的路径。例如,在C++代码库上运行LGTM.com查询套件(以生成SARIF格式的返回结果)时,只需执行下列命令即可:
codeql database analyze
运行某个目录中的所有查询
我们可以通过提供目录路径来运行位于某个目录中的所有的查询,而不是单独列出所有的查询文件。由于路径是递归搜索的,因此,包含在子文件夹中的所有查询也都会被执行。
需要注意的是,在执行database analyze命令时,不要指定QL包的根目录,因为该目录中包含一些特殊的查询,而这些查询并不是供这些命令使用的。相反,如果需要运行大量相关查询的话,只需运行某个LGTM.com查询套件即可。例如,要执行包含在Functions目录中的所有Python查询,可以执行如下所示的命令:
codeql database analyze
上面的命令将生成一个SARIF格式的结果文件。其中,指定--format=sarif-latest的作用是,确保根据CodeQL支持的最新SARIF规范对返回结果进行格式化处理。
返回结果
对于使用CLI生成的分析结果来说,它们会为每条警示提供以下信息:
需要注意的是,我们可以把这些结果文件集成到自己的代码审查或调试设施中。例如,借助于IDE 中查看SARIF文件的插件,以及SARIF 文件的输出结果,我们可以让警报在源代码中相应的位置处以显眼的形式显示。
在CodeQL CLI中使用自定义查询
概述
通过编写自定义的查询,我们就能实现满足特殊要求的分析过程,从而突出显示特定的漏洞或错误。接下来,我们将为读者详细如何编写自定义的查询,以便与database analyze命令结合使用,从而产生解释型的返回结果。
编写有效的查询
在运行自定义的分析代码之前,首先需要编写一个有效的查询,并将其保存到扩展名为.ql的文件中。关于如何编写查询的知识,请参阅本系列中前面的文章。
提供查询元数据
查询元数据通常位于在每个查询文件的顶部,其作用是向用户提供有关该查询的说明信息,并告诉CodeQL CLI如何处理查询结果。
当我们使用database analyze命令运行查询代码时,必须提供以下两个属性,以确保能够正确的解释结果:
· 查询标识符(@id):由小写字母或数字组成的单词序列,用“/”或“-”作为分隔符,用于对查询进行标识和分类。
· 查询类型(@kind):用以表示查询结果是警报(@kind problem)还是路径(@kind path-problem)。
有关这些元数据属性的详细介绍,请参阅https://help.semmle.com/QL/learn-ql/writing-queries/query-metadata.html和https://github.com/Semmle/ql/blob/master/docs/query-metadata-style-guide.md#metadata-area。
需要注意的是,如果要将查询与其他应用程序一起使用的话,这时对于元数据的要求可能会有所不同,详情请参阅https://help.semmle.com/QL/learn-ql/writing-queries/introduction-to-queries.html#query-metadata以及https://help.semmle.com/QL/learn-ql/。
创建自定义QL包
在编写自己的查询代码时,应该将它们保存在自定义的QL包目录中。实际上,QL包可以为我们提供了一种组织CodeQL分析过程所用到的文件的方法。这个目录必须在根目录下提供一个名为qlpack.yml的文件。而我们的自定义查询必须存放在QL包根目录或其子目录中。
对于每个QL包来说,qlpack.yml文件中的信息可用于告诉CodeQL下列信息:如何编译相应的查询代码,这个包依赖哪些库,以及在哪里找到查询套件的定义。至于需要在这个文件中提供什么内容的详细介绍,请参阅https://help.semmle.com/codeql/codeql-cli/reference/qlpack-overview.html#qlpack-yml。
更新CodeQL数据库
概述
由于CodeQL CLI工具和查询是不断变化的,因此,我们之前下载的某些CodeQL数据库很可能已经过时了,换句话说,这些数据库已经不适合直接拿来就用了。
通常来说,出现下列情况时,说明数据库会已经过时:
· 对于使用CodeQL CLI创建的数据库来说,用于创建它的CLI工具的版本小于CodeQL库的副本的版本时,说明该数据库就已经太旧了。
· 对于从LGTM.com网站下载的数据库来说,LGTM.com用于创建该版本代码的CodeQL工具的版本小于CodeQL库的副本的版本时,说明数据库已经太旧了。
最对数据库进行分析之前,必须先对已经过时的数据库进行更新。接下来,我们将为读者详细介绍如何使用database upgrade子命令来更新CodeQL数据库。
先决条件
对于从LGTM.com下载的存档数据库来说,在进行更新之前,必须先解压缩。
运行codeql database upgrade命令
我们可以通过运行以下命令来更新CodeQL数据库:
codeql database upgrade
其中,有关更新数据库时可以使用的所有选项的详细信息,请参阅https://help.semmle.com/codeql/codeql-cli/commands/database-upgrade.html。
进度与结果
当我们执行database upgrade命令时,CodeQL会查找与该数据库相关的模式的版本,从而搞清楚该数据库要想跟我们的查询和库一起工作,还需要做些什么。如果需要的话,它会覆盖数据库,或者如果数据库是兼容的(或者如果它没有找到关于如何执行更新的信息),则不做任何更改。一旦数据库完成更新后,就无法“回到从前”了,换句话说,它就再也无法与旧版本的CodeQL工具一起使用了。
小结
在前面的文章中,我们为读者介绍了如何在命令行环境下构建CodeQL数据库。在本文中,则为读者详细展示了如何在命令行环境下通过查询代码来分析这些数据库、自定义查询以及更新数据库。在接下来的文章中,我们会继续为大家介绍CodeQL平台方面的相关知识。
备注:本系列文章乃本人在学习CodeQL平台过程中所做的笔记,希望能够对大家有点滴帮助——若果真如此的话,本人将备感荣幸。
参考资料:https://help.semmle.com/
发表评论