GitHub CodeQL 语义分析
什么是 GitHub CodeQL?
CodeQL 是 GitHub 推出的一款语义代码分析引擎。与传统的静态分析工具不同,它不只进行模式匹配或语法检查,而是将你的代码当作数据来查询。它通过构建一个完整的代码数据库,把源码解析为关系型表示,然后你可以像查询数据库一样编写查询来发现各类漏洞、错误与模式。
- 语义分析:理解代码的“含义”,能够识别数据流、控制流、类型层级等。
- 变体分析:找到某个已知漏洞的所有相似形态,而不仅仅是字面匹配。
- 集成于 CI/CD:通过 GitHub Actions 自动扫描每个拉取请求,防止问题合入主分支。
环境准备与基础概念
安装 CodeQL CLI 与 VS Code 扩展
- 下载 CodeQL CLI 二进制包。
- 解压并配置环境变量,使
codeql命令全局可用。 - 在 VS Code 中搜索并安装 CodeQL 扩展。
- 将下载的 CLI 目录路径填入扩展设置 “CodeQL CLI Executable Path”。
之后你便可以直接在编辑器里编写、执行查询并查看结果。
核心概念:数据库与查询
- CodeQL 数据库:包含代码的抽象语法树(AST)、数据流关系、控制流图、类型信息等。可通过
codeql database create <db-name>创建。 - QL 包:可复用的查询或库的集合,通常结构为
codeql-<语言>-queries。 - 查询文件:以
.ql为后缀,包含一个或多个from...where...select子句。
QL 语言快速入门
逻辑查询与类声明
QL 是一种声明性、面向对象的查询语言,核心结构为:
from Variable v, VariableUse use
where v = use.getTarget() and
v.getName() = "password"
select use, "变量 'password' 的不可信引用"
你还可以定义类来描述特定类型的代码元素:
class SensitiveVariable extends Variable {
SensitiveVariable() {
this.getName().regexpMatch("secret|password|token")
}
}
这样在后续查询中就可以直接使用 SensitiveVariable。
数据流分析
CodeQL 的真正威力在于数据流。它提供了多个标准库模块来实现污点追踪。
import cpp
import semmle.code.cpp.dataflow.DataFlow
from DataFlow::Node source, DataFlow::Node sink
where source = /* 危险输入源 */ and
sink = /* 潜在不安全汇点 */ and
DataFlow::flow(source, sink)
select sink, "未经验证的输入流入危险函数"
运用 DataFlow::flow 可以帮助你发现跨函数、跨文件的污点传播路径。
创建你的第一个代码扫描分析
1. 生成 CodeQL 数据库
以 Java 项目为例:
codeql database create my-db --language=java --command="mvn clean compile"
--command 应包含构建项目所需的完整指令。
2. 编写查询:不安全的反序列化
新建 UnsafeDeserialization.ql:
/**
* @name 不安全的反序列化
* @description 识别出从不可信数据源直接进行 Java 反序列化的位置
* @kind path-problem
* @id java/unsafe-deserialization
*/
import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.ExternalFlow
class UntrustedSource extends SourceNode {
UntrustedSource() { this.asExpr() instanceof RemoteInput }
}
class DeserializationSink extends SinkNode {
DeserializationSink() {
exists(MethodAccess ma |
ma.getMethod().hasName("readObject") or
ma.getMethod().hasName("readUnshared")
|
this.asExpr() = ma.getQualifier()
)
}
}
from UntrustedSource src, DeserializationSink sink, DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode
where DataFlow::flowPath(src, sink) and
flowPath(sourceNode, sinkNode)
select sinkNode, sourceNode, sinkNode, "不可信数据流入 $@.", sinkNode, "反序列化调用"
path-problem类型的查询可以生成可追踪的数据流路径。- 利用
RemoteInput识别出网络或用户输入来源。 DataFlow::flowPath捕获完整路径供查看。
3. 运行查询并解读结果
codeql query run UnsafeDeserialization.ql --database=my-db --output=results.bqrs
codeql bqrs decode --format=csv results.bqrs --output=results.csv
VS Code 扩展可以直接将结果以高亮路径形式展示在编辑器中,每条告警均可点击查看数据从源到汇的完整步骤。
将分析集成到 GitHub 仓库
使用默认的 CodeQL 工作流
在仓库的 .github/workflows/codeql.yml 中启用:
name: "CodeQL"
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
security-events: write
steps:
- uses: actions/checkout@v3
- uses: github/codeql-action/init@v2
with:
languages: java
- run: |
mvn clean compile
- uses: github/codeql-action/analyze@v2
每次推送代码,GitHub 都会执行分析并将安全告警推送到仓库的“Security”选项卡下。
自定义查询包
可以将自己写的 .ql 文件放入 .github/codeql/custom-queries 目录,并在工作流中指定:
- uses: github/codeql-action/init@v2
with:
queries: .github/codeql/custom-queries
这样你的专用规则就会与内置查询一起运行。
高级语义分析技巧
函数建模与数据流扩展
当默认的数据流规则无法识别某些自定义框架时,你可以自行添加建模:
- 源定义:
class MySource extends DataFlow::Node { ... } - 阶梯谓词:
MySource::flowsTo(DataFlow::Node sink) - 利用 QL 的
override机制扩展现有TaintTracking配置。
例如,用于识别通过自定义 @Secured 注解标记的函数返回值不应被视为可信输入。
跨模块分析
针对多模块、多仓库的项目,CodeQL 支持将多个数据库视为一个联合数据库进行分析,只需在创建数据库时指定额外模块目录:
codeql database create combined-db --language=java --command="..." --source-root=.
自定义类继承检测
检查抽象类或接口的不正确实现:
from Interface i, Class c
where c.getAnAncestor() = i and
not c.declaresMethod(i.getAMethod())
select c, "未实现接口 " + i.getName() + " 中的方法"
排查常见问题
- 数据库创建失败:检查
--command使用的构建指令是否能在当前环境无错执行。 - 查询无结果:确认查询中的谓词是否匹配实际代码结构。可以用
select any()快速查看元素数量。 - 性能过慢:避免使用无限制的递归,为复杂类添加
exists约束。 - 扩展无法加载:确保
qlpack.yml正确声明依赖,并在 VS Code 中通过CodeQL: Install Pack Dependencies安装。
总结与学习路径
CodeQL 的语义分析能力为代码安全审查与缺陷发现带来了质变。从基础的查询语法,到复杂的数据流变体分析,再到 CI/CD 全自动集成,它提供了一套覆盖研发全流程的现代化代码健康保障体系。
下一步你可以:
- 阅读官方 QL 语言参考。
- 在 CodeQL Cookbook 中探索数百个真实查询范例。
- 参与 GitHub Security Lab 的漏洞研究项目。
开始用语义的力量,重新审视你的代码。