关于 opengrep
Opengrep 是从 Semgrep 分叉的开源静态分析和结构化代码搜索命令行工具。开发者可沿用 Semgrep 规则,扫描安全问题或匹配代码模式。
主要功能
- 01基于 AST 的结构化代码搜索
- 02使用规则集进行安全扫描
- 03自定义 YAML 规则与污点分析
- 04输出 SARIF 和 JSON
- 05规则测试与校验
- 06支持 Windows
适用场景
- 01查找特定调用并减少文本搜索噪声
- 02扫描代码中的常见漏洞
- 03追踪不可信数据流向风险操作
- 04应用自定义规则前进行测试
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ opengrep/ skills --skill opengrep安装后在 Claude Code 中输入/opengrep确认已加载。
详细介绍
Opengrep 静态分析
Opengrep 是一个由社区维护的开源静态分析工具,分叉自 Semgrep。它使用相同的规则语法和 CLI 接口,因此现有 Semgrep 规则和知识可以迁移使用。
两种使用场景
1. 语义代码搜索(grep 的替代方案)
探索代码库时,grep 可以查找文本模式,但会遗漏结构模式。Opengrep 能理解代码结构:
| 任务 | Grep | Opengrep |
|---|---|---|
| 查找文本“execute” | 快速有效 | 大材小用 |
查找 cursor.execute(...) 调用 | 可能匹配注释和字符串 | 只匹配实际调用 |
查找调用 os.system 的函数 | 很难 | pattern-inside + pattern |
| 查找未参数化的 SQL 查询 | 几乎不可能 | 污点模式 |
在以下情况下使用 Opengrep:
- 需要查找带有特定参数的函数/方法调用
- grep 返回了过多误报(匹配到注释、字符串或相似名称)
- 需要查找特定上下文中的模式(循环内、try 块内)
- 模式具有结构含义,而不只是文本
在以下情况下继续使用 grep:
- 简单的文本搜索
- 速度至关重要
- 模式是字面字符串或简单正则表达式
2. 安全扫描
运行规则集以检测漏洞和不安全模式。
安装
Linux / macOS
curl -fsSL https://raw.githubusercontent.com/opengrep/opengrep/main/install.sh | bash
Windows(PowerShell)
irm https://raw.githubusercontent.com/opengrep/opengrep/main/install.ps1 | iex
手动安装
从发布页面下载二进制文件。
验证
opengrep --version
macOS、Linux 和 Windows 均提供独立运行的二进制文件。无需 Python。
运行 opengrep scan --help 可查看所有可用选项和标志。
代码搜索模式
快速单行命令
# Find all calls to a function
opengrep scan -e 'dangerous_function(...)' -l python .
# Find method calls on specific objects
opengrep scan -e '$OBJ.execute(...)' -l python .
# Find assignments to a variable name
opengrep scan -e '$VAR = os.environ.get(...)' -l python .
# Find function definitions
opengrep scan -e 'def $FUNC(...): ...' -l python .
性能说明
Opengrep 会将整个文件解析为 AST。进行快速文本搜索时,grep 的速度要快 10 到 100 倍。只有在结构匹配值得付出额外开销时,才使用 Opengrep。
安全扫描
快速扫描
# Scan with a ruleset
opengrep scan --config p/security-audit .
# Multiple rulesets
opengrep scan --config p/security-audit --config p/owasp-top-ten .
# Scan specific paths
opengrep scan --config p/python src/
输出格式
# SARIF for tooling
opengrep scan --config p/default --sarif -o results.sarif .
# JSON for automation
opengrep scan --config p/default --json -o results.json .
# Show data flow traces
opengrep scan --dataflow-traces -f rule.yaml .
# Include enclosing context (function/class) in JSON output (experimental)
opengrep scan --output-enclosing-context --json -f rule.yaml . --experimental
筛选
# By severity
opengrep scan --config p/default --severity ERROR .
# By path
opengrep scan --config p/default --include='src/**' --exclude='**/test/**' .
# Apply exclusions to explicitly passed file targets (not just directory scan roots)
opengrep scan --force-exclude --exclude='**/vendor/**' -f rule.yaml vendor/lib.py
文件内跨函数污点追踪
Opengrep 支持在文件内跨函数追踪污点:
opengrep scan --taint-intrafile -f taint-rule.yaml .
这使高阶函数支持成为可能,类似于 Semgrep Pro 的 --pro-intrafile。
编写自定义规则
基本规则结构
rules:
- id: hardcoded-secret
languages: [python]
message: "Hardcoded secret detected in $VAR"
severity: ERROR
patterns:
- pattern: $VAR = "$VALUE"
- metavariable-regex:
metavariable: $VALUE
regex: ^sk_live_
规则 ID 唯一性
重要:在一个配置中,所有规则的 ID 必须唯一。如果多条规则共用同一个 ID,由于加载规则时会进行去重,因此只会使用其中一条。
编写针对多种语言的规则时,这一点尤其重要。即使规则针对不同语言,也不能重复使用同一个规则 ID:
# WRONG - both rules have id: taint, only one will be active
rules:
- id: taint
languages: [python]
pattern: dangerous_call(...)
# ...
- id: taint
languages: [rust]
pattern: unsafe_fn(...)
# ...
# CORRECT - unique IDs for each rule
rules:
- id: taint-python-dangerous-call
languages: [python]
pattern: dangerous_call(...)
# ...
- id: taint-rust-unsafe-fn
languages: [rust]
pattern: unsafe_fn(...)
# ...
使用包含语言或上下文信息的描述性 ID,以避免冲突。
模式语法
| 语法 | 含义 |
|---|---|
... | 匹配零个或多个参数/语句 |
$VAR | 元变量(捕获任意表达式) |
$...ARGS | 省略号元变量(捕获零个或多个参数) |
<... $X ...> | 深层表达式匹配(嵌套) |
模式运算符
| 运算符 | 用途 |
|---|---|
pattern | 匹配精确模式 |
patterns | 必须全部匹配(AND) |
pattern-either | 任意一个匹配即可(OR) |
pattern-not | 排除匹配项 |
pattern-inside | 必须位于上下文中 |
pattern-not-inside | 不得位于上下文中 |
pattern-regex | 正则表达式匹配 |
metavariable-regex | 按正则表达式筛选捕获值 |
metavariable-comparison | 比较捕获值 |
组合模式
rules:
- id: dangerous-deserialization
languages: [python]
message: "Unsafe pickle load on potentially untrusted data"
severity: ERROR
patterns:
- pattern-either:
- pattern: pickle.load(...)
- pattern: pickle.loads(...)
- pattern-not-inside: |
def $FUNC(...):
...
污点模式
用于跟踪从源到汇的数据流:
rules:
- id: sql-injection
languages: [python]
message: "User input flows to SQL query without parameterization"
severity: ERROR
mode: taint
pattern-sources:
- pattern: request.args.get(...)
- pattern: request.form[...]
pattern-sinks:
- pattern: cursor.execute($QUERY, ...)
focus-metavariable: $QUERY
pattern-sanitizers:
- pattern: int(...)
- pattern: escape(...)
污点分析的关键概念:
- 源:不可信数据进入的位置
- 汇:数据变得危险的位置
- 净化器:使数据变得安全的内容
YAML 易错点
模式是 YAML 字符串值。任何包含 : (冒号加空格)的模式都会被误解为 YAML 映射,并导致验证错误。请务必为这类模式加引号:
# BROKEN -- YAML parser sees "shell: true" as a nested mapping
- pattern: spawn($CMD, { ..., shell: true, ... })
# CORRECT -- quoted string, parsed as a single pattern value
- pattern: "spawn($CMD, { ..., shell: true, ... })"
常见触发内容:shell: true、mode: 0o777、redirect: "follow"、error: $ERR。不确定时,请为模式加引号。
对于同时包含双引号和冒号的模式,请使用转义的内部引号:
- pattern: "fetch($URL, { ..., redirect: \"follow\", ... })"
扫描非代码文件(通用语言)
对于 XML 配置、YAML 流水线、Dockerfile 和其他非代码文件,结构化模式可能无法生效。请使用 languages: [generic] 搭配 pattern-regex:
rules:
- id: cleartext-traffic
patterns:
- pattern-regex: 'cleartextTrafficPermitted\s*=\s*"true"'
languages: [generic]
severity: WARNING
paths:
include:
- "app/src/"
paths 键可限制规则适用的文件:
paths:
include:
- ".github/workflows/" # Only scan GHA workflow files
exclude:
- "test/" # Skip test directories
注意:虽然存在 languages: [dockerfile],但 pattern-not-inside 在多个 Dockerfile 指令间无法可靠工作。对于跨多行的 Dockerfile 安全检查,建议使用 generic 搭配正则表达式。
metavariable-pattern
使用 metavariable-pattern 限制元变量可匹配的内容。它必须作为列表项放在 patterns: 内,与捕获该元变量的模式并列:
rules:
- id: dynamic-property-assignment
patterns:
- pattern: $OBJ[$KEY] = $VALUE
- metavariable-pattern:
metavariable: $KEY
patterns:
- pattern-not: "..." # Exclude literal string keys
languages: [typescript, javascript]
severity: WARNING
这与 metavariable-regex 不同,后者按正则表达式而非模式进行筛选。
模式解析限制
某些语言结构无法作为独立片段进行匹配:
catch块:单独使用catch ($ERR) { ... }无效。必须包含try:try { ... } catch ($ERR) { ... }。即便如此,catch代码块中复杂的省略号在 TypeScript 中仍可能无法解析。- 变通方法:直接匹配危险表达式,而不是将其放在 try/catch 上下文中。
规则选项(Opengrep 专用)
rules:
- id: expensive-rule
options:
timeout: 10 # Per-rule timeout (requires --allow-rule-timeout-control)
dynamic_timeout: true # Scale timeout with file size
max_match_per_file: 100 # Limit matches per file
# ... rest of rule
使用 --allow-rule-timeout-control 启用逐规则超时设置。
测试规则
测试文件注释
在预期发现项的上一行放置 # ruleid:(对于污点规则,放在汇处之前):
# test_rule.py
def vulnerable():
user_id = request.args.get("id")
# ruleid: sql-injection
cursor.execute("SELECT * FROM users WHERE id = " + user_id)
def safe():
user_id = int(request.args.get("id"))
# ok: sql-injection
cursor.execute("SELECT * FROM users WHERE id = " + user_id)
运行测试
# Test a rule (supports multiple target files)
opengrep test --config rule.yaml test_file.py test_file2.py
# Validate rule syntax (positional argument, not --config)
opengrep validate rule.yaml
# Debug taint flow
opengrep scan --dataflow-traces -f rule.yaml test_file.py
配置
.semgrepignore
Opengrep 使用 .semgrepignore 以保持兼容性。通过 --semgrepignore-filename 指定自定义文件名:
# Ignore directories
vendor/
node_modules/
**/testdata/
# Ignore patterns
*.min.js
*.generated.go
行内抑制
默认注释标记:nosemgrep、nosem、noopengrep(均可使用):
password = get_from_vault() # nosemgrep: hardcoded-password
password = get_from_vault() # nosem: hardcoded-password
password = get_from_vault() # noopengrep: hardcoded-password
使用 --opengrep-ignore-pattern 添加其他模式:
# Add nosec as an additional suppression annotation
opengrep scan --opengrep-ignore-pattern='nosec' -f rule.yaml .
规则元数据
rules:
- id: command-injection
metadata:
category: security
subcategory:
- vuln # vuln = confirmed vulnerability, audit = needs review
cwe:
- "CWE-78: Improper Neutralization of Special Elements used in an OS Command"
owasp:
- "A03:2021 - Injection"
confidence: HIGH # HIGH, MEDIUM, or LOW
references:
- https://owasp.org/Top10/A03_2021-Injection/
# ... rest of rule
工具会使用 category/subcategory/confidence 字段对发现项进行分类和筛选。对于高置信度漏洞,请使用 subcategory: [vuln];对于需要人工审查的模式,请使用 subcategory: [audit]。
使用 --inline-metavariables 在元数据输出中包含元变量值。
常用规则集
| 规则集 | 重点 |
|---|---|
p/security-audit | 全面的安全规则 |
p/owasp-top-ten | OWASP Top 10 漏洞 |
p/cwe-top-25 | CWE Top 25 漏洞 |
p/python / p/javascript / p/golang | 特定语言 |
注意:可用的规则集可能与 Semgrep 注册表不同。
与 Semgrep 的区别
Opengrep 是从 Semgrep 1.100.0 分叉而来。主要区别:
- 开放 Semgrep Pro 功能:文件内跨函数污点分析(
--taint-intrafile)、高阶函数支持和方法间污点流——均无需商业许可证即可使用 - 更多语言:Visual Basic(Semgrep CE 和 Pro 均不支持)、Apex、Elixir(Semgrep CE 不支持),以及增强了污点支持的 Clojure
- Windows:原生支持
- 单规则超时:规则选项
timeout和dynamic_timeout - 匹配数量限制:规则选项
max_match_per_file和 CLI 标志--max-match-per-file - 上下文输出:
--output-enclosing-context可显示函数/类上下文 - 自定义忽略模式:
--opengrep-ignore-pattern可扩展默认抑制规则
完整更新日志见:https://github.com/opengrep/opengrep/blob/main/OPENGREP.md
现有的 Semgrep 规则和文档通常也适用。
资源
- Opengrep:https://github.com/opengrep/opengrep
- Semgrep 规则语法(兼容):https://semgrep.dev/docs/writing-rules/rule-syntax