自定义规则集

  • 引入于 13.5 版本。
  • 添加了对透传链的支持。在版本 14.6 中,扩展为包括额外的传递类型的 filegiturl
  • 对覆盖规则的支持添加于 14.8 版本。

您可以自定义我们的 SAST 分析器提供的默认扫描规则。 规则集自定义支持可同时使用的以下内容:

要自定义默认扫描规则,请创建一个包含自定义规则的文件。这些规则被传递到分析器的底层扫描工具。

创建自定义规则集:

  1. 在项目的根目录下创建一个 .gitlab 目录,如果该目录尚不存在。
  2. .gitlab 目录下创建一个名为 sast-ruleset.toml 的自定义规则集文件。

禁用预定义的分析器规则

要禁用分析器规则:

  1. ruleset 部分的上下文中将 disabled 标志设置为 true

  2. 在一个或多个 ruleset.identifier 中,列出您要禁用的规则。每个 ruleset.identifier 都有:

  • 一个 type 字段,用于命名目标分析器使用的预定义规则标识符。
  • 一个 value 字段,用于命名要禁用的规则。

示例:禁用 SAST 分析器的预定义规则

在以下示例中,通过匹配标识符的 typevalue 将禁用的规则分配给 eslintsobelow

[eslint]
  [[eslint.ruleset]]
    disable = true
    [eslint.ruleset.identifier]
      type = "eslint_rule_id"
      value = "security/detect-object-injection"

  [[eslint.ruleset]]
    disable = true
    [eslint.ruleset.identifier]
      type = "cwe"
      value = "185"

[sobelow]
  [[sobelow.ruleset]]
    disable = true
    [sobelow.ruleset.identifier]
      type = "sobelow_rule_id"
      value = "sql_injection"

那些包含提供的类型和值的漏洞现在被禁用,这意味着它们不会显示在合并请求或漏洞报告中。

覆盖预定义的分析器规则

要覆盖分析器规则:

  1. 在一个或多个 ruleset.identifier 中,列出您要覆盖的规则。每个 ruleset.identifier 都有:

    • 一个 type 字段,用于命名目标分析器使用的预定义规则标识符。
    • 一个 value 字段,用于命名要覆盖的规则。
  2. ruleset 部分的 ruleset.override 上下文中,提供要覆盖的键。可以覆盖任何键组合。有效的键是:

    • description
    • message
    • name
    • severity(有效选项为:Critical、High、Medium、Low、Unknown、Info)

示例:覆盖 SAST 分析器的预定义规则

在添加规则集之前,我们通过查看 gl-sast-report.json 来验证哪个漏洞将被覆盖:

"identifiers": [
        {
          "type": "gosec_rule_id",
          "name": "Gosec Rule ID G307",
          "value": "G307"
        },
        {
          "type": "CWE",
          "name": "CWE-703",
          "value": "703",
          "url": "https://cwe.mitre.org/data/definitions/703.html"
        }
      ]

在以下示例中,来自 gosec 的规则由标识符的 typevalue 匹配,然后被覆盖:

[gosec]
  [[gosec.ruleset]]
    [gosec.ruleset.identifier]
        type = "CWE"
        value = "703"
    [gosec.ruleset.override]
      severity = "Critical"

如果发现类型为 CWE 且值为 703 的漏洞,则漏洞严重性将被覆盖为 Critical

合成自定义配置

要创建自定义配置,您可以使用透传链。

透传是透传链中的一个步骤。按顺序评估透传,逐步构建配置。然后将配置传递给目标分析器。

分析器的配置部分具有以下参数:

参数 说明
description 关于分析器配置部分的说明。
targetdir targetdir 参数定义了最终配置所在的目录。如果 targetdir 为空,则分析器使用随机目录。targetdir 的最大大小为 100MB。
validate 如果设置为 true,则验证传递的目标文件(rawfileurl)。验证适用于 yamlxmljsontoml 文件。根据目标文件的扩展名识别正确的验证器。默认情况下,validate 设置为 false
interpolate 如果设置为 true,则启用环境变量插值,以便配置使用 secret/令牌。 我们建议谨慎使用此功能,不要泄露任何 secret。默认情况下,interpolate 设置为 false
timeout 评估透传链的 timeout 设置为 60 秒。如果未设置 timeout,则默认超时为 60 秒。超时不能超过 300 秒。

配置部分可以包括一个或多个透传部分。透传部分的最大数量为 20。 有几种类型的透传:

类型 描述
file 使用 Git 仓库中已有的文件。
raw 提供行内配置。
git 从远端 Git 仓库中提取配置。
url 通过 HTTP 获取分析器配置。

如果在透传链中定义了多个透传部分,则它们在链中的位置定义了它们的评估顺序。

  • 链序列中后面列出的透传具有更高的优先级。
  • 具有更高优先级的透传覆盖(默认)并附加先前透传产生的数据,对于需要使用或修改现有配置的情况很有用。

配置透传的以下参数:

参数 说明
type filerawgiturl 之一。
target 包含透传评估写入的数据的目标文件。如果未提供任何值,则会生成一个随机目标文件。
mode overwrite:如果 target 存在,覆盖文件;append:改为追加到文件。默认值为 overwrite
ref 此选项仅适用于 git 直通类型,并包含要使用的分支名称或 SHA。使用分支名称时,请以 refs/heads/<branch> 的形式指定,而不是 refs/remotes/<remote_name>/<branch>
subdir 此选项仅适用于 git 直通类型,可用于仅考虑源 Git 仓库的某个子目录。
value 对于 fileurlgit 类型,value 定义了文件/Git 仓库的源位置;对于 raw 类型,value 携带要传递的原始内容。
validator 可用于在应用透传后,在目标文件上显式调用验证器(xmlyamljsontoml)。默认情况下,没有设置验证器。

单次透传产生的数据量限制为 1MB。

透传配置示例

nodejs-scan 的原始透传

定义自定义分析器配置。在此示例中,为 nodejs-scan 扫描器定义了自定义规则:

[nodejs-scan]
  description = 'custom ruleset for nodejs-scan'

  [[nodejs-scan.passthrough]]
    type  = "raw"
    value = '''
- nodejs-extensions:
  - .js

  template-extensions:
  - .new
  - .hbs
  - ''

  ignore-filenames:
- skip.js

  ignore-paths:
  - __MACOSX
  - skip_dir
  - node_modules

  ignore-extensions:
  - .hbs

  ignore-rules:
  - regex_injection_dos
  - pug_jade_template
  - express_xss

'''

Gosec 的文件透传

提供包含自定义分析器配置的文件的名称。在本例中,gosec 扫描器的自定义规则包含在 gosec-config.json 文件中:

[gosec]
  description = 'custom ruleset for gosec'

  [[gosec.passthrough]]
    type  = "file"
    value = "gosec-config.json"

Semgrep 的透传链

在下面的示例中,我们在 /sgrules 目标目录下生成一个自定义配置,总 timeout 为 60 秒。

几种透传类型为目标分析器生成配置:

  • 两个 git 透传部分从 myrules Git 仓库中提取分支 refs/heads/test 的头部,并从 sast-rules Git 仓库中提取 revision 97f7686。在 sast-rules Git 仓库中,仅考虑来自 go 子目录的数据。
    • sast-rules 条目具有更高的优先级,因为它稍后出现在配置中。
    • 如果两个仓库中的文件之间存在文件名冲突,则来自 sast 仓库的文件会覆盖来自 myrules 仓库的文件,因为 sast-rules 具有更高的优先级。
  • raw 条目在 /sgrules 下创建一个名为 insecure.yml 的文件。完整路径是 /sgrules/insecure.yml
  • url 条目获取通过 URL 提供的配置并将其存储在 /sgrules/gosec.yml 文件中。

之后,使用位于 /sgrules 下的最终配置调用 Semgrep。

[semgrep]
  description = 'semgrep custom rules configuration'
  targetdir = "/sgrules"
  timeout = 60

  [[semgrep.passthrough]]
    type  = "git"
    value = "https://gitlab.com/user/myrules.git"
    ref = "refs/heads/test"

  [[semgrep.passthrough]]
    type  = "git"
    value = "https://gitlab.com/gitlab-org/secure/gsoc-sast-vulnerability-rules/playground/sast-rules.git"
    ref = "97f7686db058e2141c0806a477c1e04835c4f395"
    subdir = "go"

  [[semgrep.passthrough]]
    type  = "raw"
    target = "insecure.yml"
    value = """
rules:
- id: "insecure"
  patterns:
  - pattern: "func insecure() {...}"
  message: |
    Insecure function insecure detected
  metadata:
    cwe: "CWE-200: Exposure of Sensitive Information to an Unauthorized Actor"
  severity: "ERROR"
  languages:
  - "go"
    """

  [[semgrep.passthrough]]
    type  = "url"
    value = "https://semgrep.dev/c/p/gosec"
    target = "gosec.yml"

插值

下面的代码片段显示了一个示例配置,该配置使用环境变量 $GITURL 通过 Git URL 访问私有仓库。该变量在 value 字段中包含用户名和令牌(例如 https://user:token@url)。 它不会在配置文件中明确地存储凭据。为了降低通过创建的路径和文件泄露机密的风险,请谨慎使用此功能。

[semgrep]
  description = 'semgrep custom rules configuration'
  targetdir = "/sgrules"
  interpolate = true

  [[semgrep.passthrough]]
    type  = "git"
    value = "$GITURL"
    ref = "refs/heads/main"

为透传配置附加模式

要将数据附加到先前的传递,请对传递类型 fileurlraw 使用 append 模式。

override 模式下的透传会覆盖链中前面的透传发现命名冲突时创建的文件。如果 mode 设置为 append,则透传会将数据附加到其前身创建的文件中,而不是覆盖。

在下面的 Semgrep 配置中,/sgrules/insecure.yml 组装了两个透传。规则是:

  • insecure
  • secret

这些规则将搜索模式添加到分析器并扩展 Semgrep 功能。

对于透传链,我们建议您启用验证。要启用验证,您可以:

  • validate 设置为 true

  • 将透传 validator 设置为 xmljsonyamltoml

[semgrep]
  description = 'semgrep custom rules configuration'
  targetdir = "/sgrules"
  validate = true

  [[semgrep.passthrough]]
    type  = "raw"
    target = "insecure.yml"
    value = """
rules:
- id: "insecure"
  patterns:
  - pattern: "func insecure() {...}"
  message: |
    Insecure function insecure detected
  metadata:
    cwe: "...
  severity: "ERROR"
  languages:
  - "go"
"""

  [[semgrep.passthrough]]
    type  = "raw"
    mode  = "append"
    target = "insecure.yml"
    value = """
- id: "secret"
  patterns:
  - pattern-either:
    - pattern: "$MASK = \"...\""
  - metavariable-regex:
      metavariable: "$MASK"
      regex: "(password|pass|passwd|pwd|secret|token)"
  message: |
    Use of Hard-coded Password
    cwe: "..."
  severity: "ERROR"
  languages:
  - "go"
"""