如何使用 Semgrep 扫描自定义 Erlang 插件的 SQL 注入?

解读

CouchDB 的核心查询语言并非 SQL,但国内不少企业会在 Erlang 插件里直接拼接 SQL 去访问外部关系型数据库(MySQL、PostgreSQL、SQL Server),以完成复杂报表或权限校验。这类插件一旦上线,就暴露在公网 5984 端口,成为攻击链最后一环。面试官问“用 Semgrep 扫 SQL 注入”,不是考你会不会写规则,而是看你是否能把CouchDB 的 Erlang 编码习惯、国内常见缺陷模式、CI 落地流程三件事串成闭环。答不到“规则怎么写”“误报怎么压”“增量怎么跑”,就会被判定为“只看过文档,没上过生产线”。

知识点

  1. CouchDB 插件加载机制:
    _plugins 路径下的 .beam 由 couch_epi 动态热加载,源码通常写在 src/ 目录,编译后打进 priv/
  2. Erlang SQL 拼接三大危险 API:
    epgsql:sql_query/2、mysql:query/2、odbc:sql_query/2;凡是出现 "SELECT ... " ++ Vario_lib:format("SELECT ... ~s", [Var]) 即为高危。
  3. Semgrep 对 Erlang 的支持:
    官方规则库仅 20 条,必须写自定义 metavariable-pattern 才能识别 Erlang 的字符串拼接函数;同时打开 generic 模式可补漏。
  4. 国内合规要求:
    《个人信息保护法》第 51 条要求**“自动化扫描+人工复核”双签字**,因此规则集必须输出 SARIF 给内部安全平台留痕。
  5. CI 集成要点:
    GitLab-CI 里用 returntocorp/semgrep-agent:erlang 镜像,MR 阶段增量扫描、主干合并后全量扫描,质量红线设为“高危 0 容忍”。

答案

  1. 建立规则文件 couchdb-erlang-sql-inject.yaml,内容如下:
    rules:
      - id: couchdb-erlang-sql-inject
        languages: [erlang]
        severity: ERROR
        message: 外部 SQL 拼接未参数化,存在注入风险
        patterns:
          - pattern-either:
              - pattern: $API:sql_query($CONN, "..." ++ $VAR)
              - pattern: $API:sql_query($CONN, io_lib:format("..." ++ "...", [$VAR]))
          - metavariable-regex:
              metavariable: $API
              regex: (epgsql|mysql|odbc)
        metadata:
          cwe: "CWE-89"
          owasp: "A03:2021"
    
  2. 本地验证:
    semgrep --config=couchdb-erlang-sql-inject.yaml src/ -o result.json --sarif
    
    确认命中行号、变量名无误后,把规则 push 到内部 GitLab 的 .semgrep/ 目录,成为组织级规则。
  3. CI 集成:
    .gitlab-ci.yml 中增加:
    semgrep:
      stage: security
      image: returntocorp/semgrep-agent:erlang
      script:
        - semgrep-agent --config=.semgrep/ --baseline=$(git merge-base HEAD origin/main)
      artifacts:
        reports:
          sast: gl-sast-report.json
      only:
        - merge_requests
        - main
    
  4. 误报降噪:
    对单元测试目录 test/paths: exclude,对内部 ORM 封装函数加 pattern-not-inside: mysafequery(...)把误报率压到 5% 以下,否则安全部会打回。
  5. 闭环处置:
    扫描结果自动同步到内部缺陷跟踪系统,高危漏洞 24h 内修复、72h 内复测,并在 Release Note 里注明“已通过 Semgrep SQL 注入专项扫描”,满足国内监管审计要求。

拓展思考

  1. 如果插件里用 erlang-elixir 互调,SQL 语句在 Elixir 端拼接后通过 Port 传回 Erlang,Semgrep 原生无法跨语言,需要写 Elixir 规则并在同一 Pipeline 里串联,否则会出现“漏扫”。
  2. 对于参数化查询但 ORDER BY 列名动态传入的场景,上述规则会误报;可再加一条 metavariable-pattern 识别 <<" ORDER BY ", Column/binary >> 并标记为“需人工复核”,实现精准分级
  3. 国内头部云厂商已要求**“双引擎交叉验证”**,可在 Semgrep 之后再接 sobelow + CodeQL,形成 Erlang 层、SQL 层、业务逻辑层三维覆盖,把高危漏洞检出率提升到 99% 以上,同时把平均修复时间 MTTR 压缩到 8 小时以内,这才是面试官想听到的“端到端安全运营”闭环。