ast-grep 安全审计指南:快速定位代码漏洞的结构匹配规则编写
你还在为代码审计中漏检漏洞或误报太多而烦恼吗?传统文本搜索工具(如grep)无法理解代码语法结构,导致安全审计效率低下。本文将带你掌握ast-grep(抽象语法树 grep)的结构匹配规则编写技术,30分钟内即可上手检测常见安全漏洞,让代码审计效率提升10倍。读完本文你将学会:
- 使用AST(抽象语法树)结构匹配精准定位漏洞
- 编写3类常见漏洞检测规则(SQL注入/硬编码密钥/不安全函数调用)
- 掌握约束条件与元变量高级用法
为什么选择ast-grep进行安全审计?
ast-grep是一款用Rust编写的CLI工具,通过解析代码生成AST(抽象语法树)实现结构化搜索。与传统工具相比,它具有以下优势:
- 语法感知:识别代码结构而非文本模式,避免因格式变化(如空格、换行)导致漏检
- 跨语言支持:内置20+编程语言解析器,包括JavaScript、Python、Java等主流语言
- 灵活规则:支持CSS选择器式节点定位和YAML配置文件,兼顾易用性与强大功能
官方文档:README.md
核心匹配逻辑实现:crates/core/src/matcher.rs
结构匹配规则基础
AST节点选择器
ast-grep使用类CSS选择器语法定位AST节点,核心语法包括:
- 直接子节点:
call_expression > identifier匹配函数调用的直接标识符子节点 - 后代节点:
function_declaration return_statement匹配函数内所有return语句 - 组合匹配:
if_statement > condition:has(comparison_operator)匹配条件含比较运算符的if语句
选择器解析逻辑:crates/config/src/rule/selector.rs
规则文件基本结构
安全审计规则通常以YAML格式保存,包含以下关键字段:
id: sql-injection
language: javascript
pattern: $FUNC($USER_INPUT)
constraints:
FUNC:
regex: /^exec|query|sql$/
USER_INPUT:
not:
kind: string_literal
message: "可能存在注入风险:避免直接拼接用户输入"
pattern:定义漏洞代码的结构模板,$变量表示任意AST节点constraints:限制变量匹配范围(如函数名正则、节点类型)message:漏洞提示信息
规则配置定义:crates/config/src/rule_config.rs
常见漏洞检测规则实战
1. SQL注入检测
漏洞特征:直接拼接用户输入到SQL语句中,如db.query("SELECT * FROM users WHERE id=" + req.params.id)
检测规则:
id: sql-injection
language: javascript
pattern: $DB.$QUERY($SQL + $INPUT)
constraints:
QUERY:
regex: /^(query|exec|execute)$/
SQL:
kind: string_literal
INPUT:
any:
- kind: identifier
matches: /^(req|request|params|body)$/
- inside:
kind: function_parameter
规则解析:
$DB.$QUERY(...)匹配数据库查询函数调用- 约束
$SQL为字符串字面量,$INPUT为用户输入相关变量 - 通过
inside条件检查输入是否来自函数参数(如Express的req.params)
2. 硬编码密钥检测
漏洞特征:代码中直接包含API密钥、密码等敏感信息,如const apiKey = "sk-1234567890abcdef"
检测规则:
id: hardcoded-secret
language: typescript
pattern: const $KEY = "$VALUE"
constraints:
KEY:
regex: /^(api|secret|key|token|password)/i
VALUE:
regex: /^[A-Za-z0-9]{16,}$/ # 匹配长字符串
not:
regex: /^(true|false|null|undefined)$/ # 排除布尔值等非密钥
关键技巧:
- 使用
regex约束匹配密钥命名规范 - 通过
not条件排除常见非敏感字符串
3. 不安全函数调用检测
漏洞特征:使用危险函数如eval()、innerHTML且参数可控,如element.innerHTML = userInput
检测规则:
id: unsafe-dom
language: html
pattern: <$TAG $ATTR=$INPUT>
constraints:
TAG:
regex: /^(div|span|script)$/
ATTR:
in: [innerHTML, outerHTML, dangerouslySetInnerHTML]
INPUT:
not:
kind: string_literal
HTML专项支持:crates/language/src/html.rs
高级规则编写技巧
元变量捕获与转换
通过metavariable-pattern捕获并验证节点属性,例如检测Java中未关闭的资源:
id: unclosed-resource
language: java
pattern: |
$RESOURCE = new $TYPE($PATH);
...
return;
constraints:
RESOURCE:
kind: variable_declarator
TYPE:
regex: /^(FileInputStream|Connection|Socket)$/
metavariable-pattern:
pattern: $RESOURCE.close()
negate: true # 确保没有调用close()
元变量处理逻辑:crates/core/src/meta_var.rs
跨文件依赖检测
结合paths和inside实现复杂规则,例如检测未授权的敏感文件访问:
id: sensitive-file-access
language: python
pattern: open($PATH, $MODE)
constraints:
PATH:
regex: /^(\/etc\/|~\/\.ssh\/|secret\.txt)/
MODE:
in: ["r", "rb"]
paths:
not:
- "tests/**" # 排除测试目录
路径匹配实现:crates/cli/src/utils/find_file.rs
审计工作流实操
1. 安装与初始化
# 使用npm安装(国内CDN加速)
npm install --global @ast-grep/cli
# 初始化规则目录
ast-grep new --rule security-audit
cd security-audit
2. 编写与测试规则
# 添加自定义规则文件
vim rules/sql-injection.yaml
# 测试规则匹配效果
ast-grep scan --rule rules/ --lang js --pattern 'db.query("SELECT " + userInput)'
测试框架实现:crates/cli/src/verify/test_case.rs
3. 批量扫描项目
# 全项目扫描并输出JSON报告
ast-grep scan --rule rules/ --project ../target-project --output result.json
# 按风险等级排序
jq '.[] | select(.severity == "high")' result.json
扫描命令实现:crates/cli/src/scan.rs
规则库与资源
- 官方规则集:schemas/ 包含各语言规则JSON Schema
- 社区安全规则:tests/verify/ 测试用例中的漏洞场景
- 在线规则调试:ast-grep playground(可通过合规渠道访问)
总结与展望
ast-grep通过结构化匹配解决了传统文本搜索的局限性,特别适合安全审计中的模式化漏洞检测。建议从以下方向深化应用:
- 结合语义分析(如数据流追踪)提升规则精准度
- 构建行业特定规则库(如区块链智能合约漏洞检测)
- 集成CI/CD流程实现漏洞自动化扫描
欢迎在项目仓库提交规则PR,共同完善安全审计生态!
点赞+收藏本文,关注作者获取更多ast-grep高级技巧。下期预告:《使用ast-grep进行供应链漏洞检测》
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



