name: semgrep type: tool description: > Semgrep是一个快速的静态分析工具,用于查找漏洞和执行代码标准。 适用于扫描代码中的安全问题或集成到CI/CD管道中。
Semgrep
Semgrep是一个高效的静态分析工具,用于查找低复杂度漏洞和定位特定代码模式。由于其易用性、无需构建代码、内置多个规则以及方便的定制规则创建,它通常是审计代码库时首先运行的工具。此外,Semgrep在CI/CD管道中的集成使其成为确保代码质量的良好选择。
主要好处:
- 防止已知漏洞和安全漏洞的重新出现
- 支持大规模代码重构,例如升级已弃用的API
- 轻松集成到CI/CD管道中
- 自定义Semgrep规则模拟实际代码的语义
- 允许在不与第三方共享代码的情况下进行安全扫描
- 扫描通常只需几分钟(而不是几小时或几天)
- 易于使用,适合开发人员和安全专业人员
何时使用
使用Semgrep时:
- 寻找易于识别模式的漏洞
- 分析单个文件(过程内分析)
- 检测系统性漏洞(代码库中的多个实例)
- 强制执行安全默认值和代码标准
- 执行快速初始安全评估
- 扫描代码前无需构建
考虑替代方案时:
- 需要分析多个文件 → 考虑Semgrep Pro Engine或CodeQL
- 需要复杂流程分析 → 考虑CodeQL
- 需要跨文件的高级污染跟踪 → 考虑CodeQL或Semgrep Pro
- 自定义内部框架分析 → 可能需要专门工具
快速参考
| 任务 | 命令 |
|---|---|
| 使用自动检测扫描 | semgrep --config auto |
| 使用特定规则集扫描 | semgrep --config="p/trailofbits" |
| 使用自定义规则扫描 | semgrep -f /path/to/rules |
| 输出到SARIF格式 | semgrep -c p/default --sarif --output scan.sarif |
| 测试自定义规则 | semgrep --test |
| 禁用指标 | semgrep --metrics=off --config=auto |
| 按严重性筛选 | semgrep --config=auto --severity ERROR |
| 显示数据流追踪 | semgrep --dataflow-traces -f rule.yml |
安装
先决条件
- Python 3.7 或更高版本(用于pip安装)
- macOS、Linux 或 Windows
- Homebrew(可选,用于macOS/Linux)
安装步骤
通过Python包安装器:
python3 -m pip install semgrep
通过Homebrew(macOS/Linux):
brew install semgrep
通过Docker:
docker pull returntocorp/semgrep
保持Semgrep更新
# 检查当前版本
semgrep --version
# 通过pip更新
python3 -m pip install --upgrade semgrep
# 通过Homebrew更新
brew upgrade semgrep
验证
semgrep --version
核心工作流程
步骤 1: 初始扫描
使用自动配置扫描评估Semgrep的有效性:
semgrep --config auto
重要: 自动模式在线提交指标。要禁用:
export SEMGREP_SEND_METRICS=off
# 或
semgrep --metrics=off --config auto
步骤 2: 选择目标规则集
使用Semgrep Registry选择规则集:
# 安全重点规则集
semgrep --config="p/trailofbits"
semgrep --config="p/cwe-top-25"
semgrep --config="p/owasp-top-ten"
# 语言特定
semgrep --config="p/javascript"
# 多个规则集
semgrep --config="p/trailofbits" --config="p/r2c-security-audit"
步骤 3: 审查和分类结果
按严重性筛选结果:
semgrep --config=auto --severity ERROR
使用输出格式以便于分析:
# SARIF用于VS Code SARIF Explorer
semgrep -c p/default --sarif --output scan.sarif
# JSON用于自动化
semgrep -c p/default --json --output scan.json
步骤 4: 配置忽略文件
创建.semgrepignore文件以排除路径:
# 忽略特定文件/目录
path/to/ignore/file.ext
path_to_ignore/
# 按扩展名忽略
*.ext
# 包含.gitignore模式
:include .gitignore
注意: 默认情况下,Semgrep跳过/tests、/test和/vendors文件夹。
如何定制
编写自定义规则
Semgrep规则是带有模式匹配语法的YAML文件。基本结构:
rules:
- id: rule-id
languages: [go]
message: 一些消息
severity: ERROR # INFO / WARNING / ERROR
pattern: test(...)
运行自定义规则
# 单个文件
semgrep --config custom_rule.yaml
# 规则目录
semgrep --config path/to/rules/
关键语法参考
| 语法/操作符 | 描述 | 示例 |
|---|---|---|
... |
匹配零个或多个参数/语句 | func(..., arg=value, ...) |
$X, $VAR |
元变量(捕获并跟踪值) | $FUNC($INPUT) |
<... ...> |
深层表达式操作符(嵌套匹配) | if <... user.is_admin() ...>: |
pattern-inside |
仅在上下文中匹配 | 循环内的模式 |
pattern-not |
排除特定模式 | 负匹配 |
pattern-either |
逻辑OR(任何模式匹配) | 多个替代方案 |
patterns |
逻辑AND(所有模式匹配) | 组合条件 |
metavariable-pattern |
嵌套元变量约束 | 约束捕获的值 |
metavariable-comparison |
比较元变量值 | $X > 1337 |
示例:检测不安全请求验证
rules:
- id: requests-verify-false
languages: [python]
message: requests.get 使用 verify=False 禁用 SSL 验证
severity: WARNING
pattern: requests.get(..., verify=False, ...)
示例:SQL注入的污染模式
rules:
- id: sql-injection
mode: taint
pattern-sources:
- pattern: request.args.get(...)
pattern-sinks:
- pattern: cursor.execute($QUERY)
pattern-sanitizers:
- pattern: int(...)
message: 潜在SQL注入,用户输入未经净化
languages: [python]
severity: ERROR
测试自定义规则
创建带注释的测试文件:
# ruleid: requests-verify-false
requests.get(url, verify=False)
# ok: requests-verify-false
requests.get(url, verify=True)
运行测试:
semgrep --test ./path/to/rules/
对于自动修复测试,创建.fixed文件(例如,test.py → test.fixed.py):
semgrep --test
# 输出: 1/1: ✓ 所有测试通过
# 1/1: ✓ 所有修复测试通过
配置
配置文件
Semgrep不需要中央配置文件。配置通过以下方式完成:
- 命令行标志
- 环境变量
.semgrepignore用于路径排除
忽略模式
在仓库根目录创建.semgrepignore:
# 忽略目录
tests/
vendor/
node_modules/
# 忽略文件类型
*.min.js
*.generated.go
# 包含.gitignore模式
:include .gitignore
抑制误报
添加内联注释以抑制特定发现:
# nosemgrep: rule-id
risky_function()
最佳实践:
- 指定确切的规则ID(而非通用的
# nosemgrep) - 解释为什么禁用该规则
- 报告误报以改进规则
自定义规则中的元数据
包含元数据以提供更好上下文:
rules:
- id: example-rule
metadata:
cwe: "CWE-89"
confidence: HIGH
likelihood: MEDIUM
impact: HIGH
subcategory: vuln
# ... 规则其余部分
高级用法
技巧和窍门
| 技巧 | 为什么有帮助 |
|---|---|
使用--time标志 |
识别慢规则和文件以优化 |
| 限制省略号使用 | 减少误报并提高性能 |
使用pattern-inside作为上下文 |
创建更清晰、更集中的发现 |
| 启用自动补全 | 加速命令行工作流程 |
使用focus-metavariable |
在输出中高亮特定代码位置 |
扫描非标准扩展
强制语言解释不常见的文件扩展名:
semgrep --config=/path/to/config --lang python --scan-unknown-extensions /path/to/file.xyz
数据流追踪
使用--dataflow-traces理解值如何流向发现:
semgrep --dataflow-traces -f taint_rule.yml test.py
示例输出:
污染来源于:
test.py
2┆ data = get_user_input()
污染到达汇点的方式:
test.py
3┆ return output(data)
多语言文件扫描
扫描嵌入语言(例如HTML中的JavaScript):
rules:
- id: eval-in-html
languages: [html]
message: JavaScript中的eval
patterns:
- pattern: <script ...>$Y</script>
- metavariable-pattern:
metavariable: $Y
language: javascript
patterns:
- pattern: eval(...)
severity: WARNING
常量传播
匹配元变量持有特定值的实例:
rules:
- id: high-value-check
languages: [python]
message: $X 高于 1337
patterns:
- pattern: function($X)
- metavariable-comparison:
metavariable: $X
comparison: $X > 1337
severity: WARNING
自动修复功能
为规则添加自动修复:
rules:
- id: ioutil-readdir-deprecated
languages: [golang]
message: ioutil.ReadDir 已弃用。使用 os.ReadDir 替代。
severity: WARNING
pattern: ioutil.ReadDir($X)
fix: os.ReadDir($X)
预览修复而不应用:
semgrep -f rule.yaml --dryrun --autofix
应用修复:
semgrep -f rule.yaml --autofix
性能优化
分析性能:
semgrep --config=auto --time
优化规则:
- 使用
paths缩小文件范围 - 最小化省略号使用
- 使用
pattern-inside首先建立上下文 - 移除不必要的元变量
管理第三方规则
使用semgrep-rules-manager收集第三方规则:
pip install semgrep-rules-manager
mkdir -p $HOME/custom-semgrep-rules
semgrep-rules-manager --dir $HOME/custom-semgrep-rules download
semgrep -f $HOME/custom-semgrep-rules
CI/CD集成
GitHub Actions
推荐方法
- 主要分支上的全面扫描使用广泛规则集(计划任务)
- 针对拉取请求的差异感知扫描使用聚焦规则
- 阻止带有未解决发现的PR(一旦成熟)
示例工作流程
name: Semgrep
on:
pull_request: {}
push:
branches: ["master", "main"]
schedule:
- cron: '0 0 1 * *' # 每月
jobs:
semgrep-schedule:
if: ((github.event_name == 'schedule' || github.event_name == 'push' || github.event.pull_request.merged == true)
&& github.actor != 'dependabot[bot]')
name: Semgrep默认扫描
runs-on: ubuntu-latest
container:
image: returntocorp/semgrep
steps:
- name: 检出主要仓库
uses: actions/checkout@v4
- run: semgrep ci
env:
SEMGREP_RULES: p/default
semgrep-pr:
if: (github.event_name == 'pull_request' && github.actor != 'dependabot[bot]')
name: Semgrep PR扫描
runs-on: ubuntu-latest
container:
image: returntocorp/semgrep
steps:
- uses: actions/checkout@v4
- run: semgrep ci
env:
SEMGREP_RULES: >
p/cwe-top-25
p/owasp-top-ten
p/r2c-security-audit
p/trailofbits
在CI中添加自定义规则
规则在同一仓库中:
env:
SEMGREP_RULES: p/default custom-semgrep-rules-dir/
规则在私有仓库中:
env:
SEMGREP_PRIVATE_RULES_REPO: semgrep-private-rules
steps:
- name: 检出主要仓库
uses: actions/checkout@v4
- name: 检出私有自定义Semgrep规则
uses: actions/checkout@v4
with:
repository: ${{ github.repository_owner }}/${{ env.SEMGREP_PRIVATE_RULES_REPO }}
token: ${{ secrets.SEMGREP_RULES_TOKEN }}
path: ${{ env.SEMGREP_PRIVATE_RULES_REPO }}
- run: semgrep ci
env:
SEMGREP_RULES: ${{ env.SEMGREP_PRIVATE_RULES_REPO }}
在CI中测试规则
name: 测试Semgrep规则
on: [push, pull_request]
jobs:
semgrep-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: "3.11"
cache: "pip"
- run: python -m pip install -r requirements.txt
- run: semgrep --test --test-ignore-todo ./path/to/rules/
常见错误
| 错误 | 为什么错误 | 正确方法 |
|---|---|---|
在私有代码上使用--config auto |
向Semgrep服务器发送元数据 | 使用--metrics=off或特定规则集 |
忘记.semgrepignore |
扫描排除目录如/vendor |
创建.semgrepignore文件 |
| 不测试带有误报的规则 | 规则产生噪音 | 添加# ok:测试案例 |
使用通用的# nosemgrep |
使代码审查更困难 | 使用# nosemgrep: rule-id并附解释 |
过度使用省略号... |
降低性能和准确性 | 尽可能使用特定模式 |
| 不在规则中包含元数据 | 使分类困难 | 添加CWE、置信度、影响字段 |
限制
- 单文件分析: 没有Semgrep Pro Engine时无法跨文件跟踪数据流
- 无需构建: 无法分析编译代码或解析动态依赖项
- 基于模式: 可能错过需要深度语义理解的漏洞
- 有限的污染跟踪: 复杂污染分析仍在发展中
- 自定义框架: 内部专有框架可能支持不佳
相关技能
| 技能 | 何时一起使用 |
|---|---|
| codeql | 用于跨文件污染跟踪和复杂数据流分析 |
| sarif-parsing | 用于在管道中处理Semgrep SARIF输出 |
资源
关键外部资源
Trail of Bits公共Semgrep规则 社区贡献的Semgrep规则用于安全审计,带有贡献指南和质量标准。
Semgrep Registry 官方Semgrep规则注册表,可按语言、框架和安全类别搜索。
Semgrep Playground 交互式在线工具用于编写和测试Semgrep规则。使用“简单模式”便于模式组合。
学习Semgrep语法 全面的Semgrep规则编写基础指南。
Trail of Bits博客:如何向组织介绍Semgrep 组织采用Semgrep的七步计划,包括试点测试、推广和CI/CD集成。
Trail of Bits博客:使用Semgrep发现goroutine泄漏 编写自定义规则检测Go特定问题的真实世界示例。