6.3 双引擎对比与分工


6.3 双引擎对比与分工

本节摘要:semgrep 与 CodeQL 不是新旧替代关系,而是轻与重的分工关系。本节先用「两张底片」的说法讲清两者的能力差异:semgrep 是词法与轻量数据流层面的快照,CodeQL 是完整语义关系的深曝光;再给出一张可决策的对比表,覆盖上手成本、规则形态、跨过程能力、建库代价与授权;然后按场景给分工建议——快筛天天跑、深挖定期跑,并把「规则沉淀」作为流水线的复利环节;接着用一个虚构但典型的注入案例走一遍双引擎协作全程;最后与《语义代码检索》划界:检索回答「代码在哪」,双引擎回答「缺陷模式是否出现」,两者在 AI 工作流里是上下游而非竞争者。

学习目标

  • 用能力与成本两个维度说清两台引擎的定位差异。
  • 按场景(自研规则、CI 反馈、深度污点、变体横扫)完成选型。
  • 演练一次「semgrep 初筛、CodeQL 确认」的双引擎协作。
  • 向同事讲清静态分析与代码检索的职责边界。
  • 把双引擎组合成一条可持续运转的流水线。

一、两张底片看同一个仓库

拍照的比喻最好用:同一个仓库,semgrep 拍的是「快照」——按规则逐文件扫一遍,几秒到几十秒出结果,看到的是代码表层形态加上污点模式补上的浅层数据流;CodeQL 拍的是「长曝光」——先把整个仓库抽成关系数据库,再让引擎在完整语义上做推导,跨函数、跨文件的数据流都能追,代价是建库要数分钟到数十分钟,且编译型语言需要真实构建环境。

没有哪张底片更好,只有哪张更适合当前问题:想知道「今天新写的代码里有没有明显坏味道」,快照够用;想知道「这个参数究竟能不能流进命令执行」,长曝光才是正解。把「轻快」与「深度」当成两个正交维度,后面的对比表就好读了。

# two_photos.txt —— 两张底片的直观对比 关注点 semgrep 快照 CodeQL 长曝光 ───────────── ───────────────────── ───────────────────── 一次扫描范围 规则 × 文本 查询 × 全库语义 跨函数追踪 浅(taint 模式有限) 深(引擎级污点) 首次等待 秒级 建库数分钟起 换仓库成本 零(直接扫) 重新建库 ​

二、能力与成本对比表

维度 semgrep CodeQL
心智模型 模式即代码 代码当数据库
起步规则量 三行起步 数十行 QL 加谓词
首次出结果 分钟级(安装即扫) 小时级(装 CLI、学 QL、建库)
语言广度 多语言覆盖面广 主打主流语言,深度优先
跨过程数据流 污点模式支持,范围有限 引擎级完整污点追踪与路径输出
建库成本 无需建库 需要;编译型语言要真实构建
CI 单次耗时 秒到分钟 分钟到小时(可增量维护数据库)
规则生态 官方注册表海量即用 官方查询库加社区查询
授权 社区版免费 查询库 MIT;研究免费;商业 CI 需授权

(stars 与版本信息以官方仓库与文档为准,2026-10 社区口径分别约 17.1k 与 10.2k。)

表的使用方法是「先定约束再选工具」:预算里没有构建环境维护人力,长曝光再好也先放下;反过来,若结论要拿去支撑安全报告,只有带完整路径证据的 CodeQL 结果够格。

三、场景化分工

  • 自定义内部规则:写「我们代码库特有的危险写法」(比如内部危险封装函数的误用),semgrep 三行就能上线,团队改规则无门槛——选 semgrep。
  • CI 快反馈:每次提交秒级反馈,不让开发者等——选 semgrep。
  • 深度污点追踪:确认「外部输入能否到达危险出口」并要完整路径证据——选 CodeQL。
  • 变体横扫:一类缺陷的模式要在多个仓库反复验证——选 CodeQL。
  • 密钥与依赖扫描:semgrep 平台同时覆盖 SCA 与密钥检测,一站式——选 semgrep。

组合成流水线才是终态:

# pipeline.txt —— 双引擎流水线与规则沉淀 每次提交 ──▶ semgrep 快筛(分钟内反馈) 每周例行 ──▶ CodeQL 建库与污点查询(深度确认) 确认发现 ──▶ 证据链登记(第 11 章) │ ▼ 缺陷模式沉淀:写成 semgrep 规则或 QL 查询 ──▶ 下次自动拦截 ​

最后一箭头常被忽视:人工确认过的缺陷模式,回头写成规则,下次自动拦截——静态分析的复利来自规则库的积累,而不是单次扫描的结果。

流水线的运转节奏也可以照抄:快筛挂在提交钩子上(开发者本地跑,秒级),深挖挂在每周定时的 CI 任务上(维护增量数据库,分钟级),规则沉淀放在每案结案时(第 11.3 节 SOP 的第十步)——三处各自异步,互不拖累。

双引擎各自的常见坑也要提前知道,避免把工具问题误当能力问题:

坑 现场 对策
semgrep 规则过宽 一条 pattern 命中数百处,淹没告警 加 pattern-inside 限定上下文,或拆成多条窄规则
semgrep 污点漏报 跨文件传播追不全 已知缺口改用 CodeQL 验证,规则只做快筛
CodeQL 建库失败 编译型语言构建环境缺失 先保证本地能完整构建,再谈建库
CodeQL 查询超时 全库污点无屏障谓词 加屏障收窄,或按目录分库
两引擎结论打架 一边报警一边静默 以 CodeQL 路径证据为准,回查 semgrep 规则是否误配

四、一次协作演练:从告警到证据

用一个典型场景把分工走活(项目为自建 Flask 演示应用,注入点为教学目的故意埋入):

  • 第一步,semgrep 快筛。p/owasp-top-ten 规则集扫出三条 WARNING,其中一条指向 os.system(拼接的用户输入)——message 提示可能的命令注入。
  • 第二步,人工初判。看命中行:os.system("ping -c 1 " + request.args.get("host"))——拼接明显,但要看 host 是否还有上游净化。往上翻两个函数没找到净化,初判「高度可疑」。
  • 第三步,CodeQL 确认。用 6.2 节的查询骨架(source 为 request.args.get、sink 为 system 首参)建库跑一遍,输出完整路径:入口函数、两次传递、拼接点、sink——数据流证据齐了。
  • 第四步,入链收口。按第 11.1 节四列记录:假设(存在命令注入)、验证命令(CodeQL 查询加 semgrep 规则)、输出(路径节点序列)、结论(已证,转第 10 章方法论处置)。

四步里两台引擎各出现一次、人工出现两次——这个比例是健康比例:工具负责穷举与证据,人负责判断与处置。

演练的两个变体,顺手各做一遍:把 semgrep 规则收紧(加 pattern-inside 限定 handler 函数内),观察告警数下降但 CodeQL 结论不变——理解「快筛的查全与查准是可以调的」;再把 CodeQL 的 source 换成 JSON 请求体读取(6.2 节改写练习),观察同一 sink 的另一条入口链——理解「长曝光的广度来自查询改写而非重复扫描」。

五、与《语义代码检索》的划界

本书读者常把这两类工具混为一谈,值得专门划界:

  • 问题不同。《语义代码检索》第 01 章《为什么grep不够》解决的是「找到代码在哪」:命名鸿沟、别名、意图检索——你要找处理注销的函数,它叫 kill_session 也能命中。双引擎解决的是「验证缺陷模式是否出现」:用户输入是否流进了命令执行。
  • 输入不同。检索接受自然语言或松散描述;双引擎接受精确的模式或查询——一个容忍模糊换来召回,一个要求精确换来证据。
  • 产出不同。检索产出「位置」;双引擎产出「位置加数据流路径加严重级别」。
  • 关系是上下游。第 10 章的 AI 挖洞流程里,模型先用检索式方法(agentic 检索、repo-map,见《语义代码检索》第 06 章《repo-map与agentic检索》)定位候选代码,再用 semgrep 与 CodeQL 验证候选缺陷——找代码与验缺陷,一个也不能少。

至于代码切分、嵌入索引这些检索侧的工程细节,本书不重讲,以《语义代码检索》第 03 章《代码切分》为准。一句话总括:检索是雷达,双引擎是探照灯——前者大范围找「哪里值得看」,后者对准一点问「到底有没有问题」。

职责对照落到操作层面:

环节 用检索 用双引擎 举例
冷启动陌生仓库 先检索建地图:入口在哪、核心模块叫什么 后置:对可疑模块快筛 repo-map 定位上传处理模块
模式已经明确 不用 引擎验证 「输入流到 system 吗」一条污点查询
模式还在成形 检索找相似历史代码助你归纳 归纳成规则后再上引擎 历史注入案例归纳出本库的 sink 集合
日常巡检 不用 双引擎流水线跑规则库 每周例行的快筛加深挖
报告取证 不用 CodeQL 路径级证据 SARIF 附进证据链(第 11.1 节)

六、交给后续章节的接口

双引擎就位后,记住三个接口:其一,扫描结果是第 10 章 AI 假设的验证器——模型说「这里可能有注入」,一条污点查询就能给出确定回答;其二,确认的模式沉淀为规则,是团队资产的积累形态;其三,SARIF 与 JSON 输出是机器可读的,可经 MCP 接进模型工具链,组织方式参考《OpenCodeReview》第 04 章《工具、MCP 与会话》。

还有一个伏笔:CodeQL 与 semgrep 的「代码模型」各自封闭——一个在数据库里,一个在规则文件里。如果你想要一张能自由遍历、源码与二进制通吃的图,那是下一章 Joern 与代码属性图的主场。

给管理者的一句话版本:两台引擎的预算叙事完全不同——semgrep 的成本几乎全在「人的规则编写时间」,CodeQL 的成本几乎全在「建库与维护的机器时间加学习时间」。前者按周见效,后者按季度见效,但后者的结论硬度(路径级证据)是前者给不了的;预算只够先上一个时,按你的报告读者是谁来决定:给开发者的及时反馈选前者,给安全评审的正式结论选后者。

本节要点回顾

  • semgrep 是快照、CodeQL 是长曝光:轻快与深度是正交维度。
  • 选型口诀:自研规则与 CI 快反馈选 semgrep;深度污点与变体横扫选 CodeQL。
  • 协作演练四步:快筛、初判、确认、入链——工具两步、人工两步是健康比例。
  • 与《语义代码检索》是上下游:那边找代码,这边验缺陷模式。

引擎解决了「怎么查」,但查询语言仍是各家方言:semgrep 的 YAML、CodeQL 的 QL。有没有一种统一的表达,能把结构、流向、依赖放进同一张可自由遍历的图,让源码和二进制说同一种话?第 07 章《代码属性图Joern》给答案。


作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U