SQL注入规则常漏报format和f-string,因Semgrep默认仅匹配execute()等显式调用,而拼接发生在字符串构造阶段;需锚点前移至插值语法、结合污点追踪与上下文排除ORM等安全模式。
SQL注入规则为什么总漏报
和
?
因为 Semgrep 默认规则大多只匹配
、
这类显式调用,而 Python 中大量 SQL 拼接发生在字符串构造阶段——
或
根本没进数据库函数体,静态分析器一眼扫过去就跳过了。
真正要捕获这类“黑洞”,得把规则锚点前移到字符串拼接行为本身,并结合上下文判断是否最终流入执行函数。实操建议:
用
同时覆盖
、
、
三类插值语法,别只盯
必须加
限制变量名含
、
、
等关键词,否则会误报日志拼接
用
+
(如
)和
(如
)做污点追踪,比纯模式匹配准得多
如何让规则不把 ORM 查询当漏洞报?
像
或
这类用法本身安全,但 Semgrep 模式若写成
就会无差别命中——它不理解
是 SQLAlchemy 的安全封装,更不知道
自动参数化。
绕过误报的关键是「白名单式排除」:
在
下用
显式排除
、
、
等 ORM 特征调用
对
类规则,加
排除包裹在
且含
import 的文件(说明项目用了 ORM)
慎用
直接排除整个函数名,比如排除
会导致漏掉原生 DB-API 调用——应限定在 ORM 上下文中排除
本地规则跑不通?检查这三处
写完 YAML 规则丢进
目录,运行却提示
或直接报错,大概率卡在这几个地方:
防SQL注入的php类库
防SQL注入的php类库
下载
YAML 缩进错位:Semgrep 对空格极其敏感,
必须顶格,其子项(如
、
)统一缩进 2 空格,多一个少一个都解析失败
语言声明写错:
不能写成
或漏掉——Semgrep 不猜语言,没声明就跳过该规则
路径未包含:用
时,确保当前目录能访问到该文件;若用
,规则必须放在
且文件名以
结尾(不是
)
为什么生产环境要禁用
单独匹配?
单独靠
这种写法,在真实代码库中基本等于无效——变量名千奇百怪(
、
、
),表名动态拼接(
),甚至 SQL 被拆成多行字符串加
拼接。这种规则只能当玩具玩。
实际可用的规则必须组合使用:
用
抓取所有疑似用户输入的变量(如
、
、
)
用
追踪该变量是否经由字符串插值进入
/
参数
最后用
排除已知安全上下文(如被
包裹、或出现在
中)
真正难的不是写一条规则,而是让多条规则协同判断「这段 SQL 构造链里有没有未经消毒的外部输入」——漏掉任意一环,要么误报炸屏,要么漏报留洞。
formatf-stringexecute()execute_many()f"SELECT * FROM users WHERE id = {user_id}""SELECT ...".format(id=user_id)pattern-eitherf".format(%f-stringmetavariable-regexsqlquerystmttaint-mode: taintsourcesrequest.args.getsinkscursor.executeUser.query.filter(User.id == user_id).all()session.execute(text("..."))text("...")text().filter()patternspattern-nottext(...).filter(.where(cursor.executepattern-not-insidetry/exceptsqlalchemypattern-notexecutesemgrep --config.semgrep/rules/No matches foundpatternspatternfocus-metavariablelanguage: pythonlang: pysemgrep --config ./rules/sql-inject.yaml--config auto.semgrep/rules/.yml.yamlpatternpattern: 'f"SELECT * FROM $TABLE WHERE id = {$ID}"'user_inputreq_idpkf"logs_{year}"+=metavariable-patternrequest.*.getargs[json.get(taint-mode: taintexecuteexecutemanypattern-not-insideescape_string()logging.info()