ルールセットのカスタマイズ

  • GitLab 13.5 で導入されました
  • パススルーチェーンをサポートGitLab 14.6で、パススルーのタイプをfile,git,url に拡張。
  • GitLab 14.8でオーバーライドルールをサポート
  • GitLab 16.2で曖昧なパススルー参照を指定できるようにしました。

スキャンするリポジトリにルールセット設定ファイルを定義することで、SASTアナライザーの動作をカスタマイズすることができます。カスタマイズには2種類あります:

  • 定義済みルールの動作の変更。これには以下が含まれます:
    • 定義済みルールの無効化すべての分析器で使用できます。
    • 定義済みのルールを無効にします。すべての分析器で使用できます。
  • パススルーを使用してカスタム設定を合成することにより、定義済みのルールを置き換えます。nodejs-scansemgrepでのみ利用可能です。

定義済みルールの無効化

どの SAST アナライザでも、定義済みのルールを無効にすることができます。

ルールを無効にすると

Semgrepベースのアナライザでは、無効化されたルールの処理が異なります:

  • パフォーマンスを向上させるため、Semgrepベースの解析器は無効化されたルールをまったくスキャンしません。
  • Semgrepベースのアナライザでルールを無効にすると、sast-ruleset.toml ファイルをデフォルトのブランチにマージした後、そのルールに対する既存の脆弱性発見が自動的に解決されます。

この動作の設定方法については、「スキーマ」および「」のセクションを参照してください。

定義済みルールの上書き

定義済みルールの特定の属性は、どのSAST分析ツールでも上書きすることができます。これは、SASTを既存のワークフローやツールに適合させる場合に便利です。例えば、組織のポリシーに基づいて脆弱性の深刻度を上書きしたり、脆弱性レポートに表示するメッセージを別のものにしたりすることができます。

この動作の設定方法については、「スキーマ」および「」のセクションを参照してください。

カスタム設定の合成

SASTアナライザによっては、事前に定義されたルールを完全に置き換えることができます:

パススルーを通してカスタマイズを提供し、実行時にパススルーチェーンにComposerされ、完全な設定を生成するために評価されます。その後、基礎となるスキャナがこの新しい設定に対して実行されます。

複数のパススルー・タイプがあり、リポジトリにコミットされたファイルやルールセット設定ファイルのインラインを使用するなど、さまざまな方法で設定を提供できます。また、チェーン内の後続のパススルーをどのように扱うかを選択することもできます。

この動作の設定方法については、「スキーマ」および「」のセクションを参照してください。

設定ファイルの作成

ルールセット設定ファイルを作成します:

  1. プロジェクトのルートに.gitlab ディレクトリを作成します(まだ存在しない場合)。
  2. .gitlab ディレクトリにsast-ruleset.toml という名前のファイルを作成します。

リモート設定ファイルの指定

16.1で導入されました

CI/CD変数に、現在のリポジトリの外に保存されているルールセット設定ファイルを使用するように設定できます。これは、複数のプロジェクトに同じルールを適用するのに役立ちます。

SAST_RULESET_GIT_REFERENCE 変数では、Git URL に似た書式でプロジェクト URI、オプションの認証、オプションの Git SHA を指定します。変数の書式は次のとおりです:

[<AUTH_USER>[:<AUTH_PASSWORD>]@]<PROJECT_PATH>[@<GIT_SHA>]
note
プロジェクトに.gitlab/sast-ruleset.toml のファイルがコミットされている場合は、そのローカル設定が優先され、SAST_RULESET_GIT_REFERENCE のファイルは使われません。

次の例では、SAST を有効にし、共有ルールセットカスタマイズファイルを使用します。この例では、ファイルはexample-ruleset-project のデフォルトブランチのパス.gitlab/sast-ruleset.toml にコミットされます。

include:
  - template: Jobs/SAST.gitlab-ci.yml

variables:
  SAST_RULESET_GIT_REFERENCE: "gitlab.com/example-group/example-ruleset-project"

高度な使用方法については、非公開リモート設定の例を参照してください。

スキーマ

トップレベルのセクション

トップレベル・セクションには、TOML テーブルとして定義された 1 つ以上の_設定セクションが_含まれます。

設定説明
[$analyzer]解析器の設定セクションを宣言します。名前は、SAST アナライザのリストで定義されているスネークケース名に従います。

設定例:

[semgrep]
...

既存のルールを変更する設定セクションを作成_したり、_カスタムルールセットを合成したりすることは避けてください。

[$analyzer] 設定セクション

[$analyzer] セクションでは、解析器の動作をカスタマイズできます。有効なプロパティは設定の種類によって異なります。

設定適用対象説明
[[$analyzer.ruleset]]定義済みルール既存のルールの変更を定義します。
interpolate全て true に設定すると、設定内で$VAR を使って環境変数を評価することができます。この機能は、シークレットやトークンを漏らさないように注意して使用してください。 (デフォルト:false)
descriptionパススルーカスタムルールセットの説明
targetdirパススルー最終的な設定を保存するディレクトリ。空の場合、ランダムな名前のディレクトリが作成されます。このディレクトリには最大 100 MB のファイルを置くことができます。
validateパススルー true に設定すると、各パススルーの内部が検証されます。バリデーションはyaml,xml,json およびtoml の内容に対して動作します。適切なバリデータは、[[$analyzer.passthrough]] セクションのtarget パラメータで使用する拡張子をもとに決定されます。(デフォルト:false)
timeoutパススルータイムアウトするまでの、パススルー・チェーンの評価に費やす最大時間。タイムアウトは300秒を超えることはできません。(デフォルト: 60)

interpolate

caution
シークレット漏洩のリスクを減らすため、この機能は注意して使用してください。

以下の例は、$GITURL 環境変数を使って非公開リポジトリにアクセスする設定です。この変数にはユーザー名とトークン(例えばhttps://user:token@url )が含まれており、設定ファイルには明示的に格納されていません。

[semgrep]
  description = "My private Semgrep ruleset"
  interpolate = true

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

[[$analyzer.ruleset]] セクション

[[$analyzer.ruleset]] セクションは、事前に定義された 1 つのルールを対象とし、変更します。このセクションは、アナライザごとに 1 つから複数まで定義できます。

設定説明
disableルールを無効にするかどうか。(デフォルト:false)
[$analyzer.ruleset.identifier]変更する定義済みルールを選択します。
[$analyzer.ruleset.override]ルールのオーバーライドを定義します。

設定例:

[semgrep]
  [[semgrep.ruleset]]
    disable = true
    ...

[$analyzer.ruleset.identifier] セクション

[$analyzer.ruleset.identifier] セクションでは、変更したい定義済みルールの識別子を定義します。

設定説明
type定義済みルールで使用される識別子のタイプ。
value定義済みルールで使用される識別子の値。

typevalue の正しい値は、アナライザが生成するgl-sast-report.json を参照することで調べることができます。このファイルは、アナライザのCIジョブからジョブのアーティファクトとしてダウンロードできます。

たとえば、以下のスニペットは、3つの識別子を持つsemgrep ルールの検出結果を示しています。JSONオブジェクトのtype およびvalue キーは、このセクションで指定する値に対応します。

...
  "vulnerabilities": [
    {
      "id": "7331a4b7093875f6eb9f6eb1755b30cc792e9fb3a08c9ce673fb0d2207d7c9c9",
      "category": "sast",
      "message": "Key Exchange without Entity Authentication",
      "description": "Audit the use of ssh.InsecureIgnoreHostKey\n",
      ...
      "identifiers": [
        {
          "type": "semgrep_id",
          "name": "gosec.G106-1",
          "value": "gosec.G106-1"
        },
        {
          "type": "cwe",
          "name": "CWE-322",
          "value": "322",
          "url": "https://cwe.mitre.org/data/definitions/322.html"
        },
        {
          "type": "gosec_rule_id",
          "name": "Gosec Rule ID G106",
          "value": "G106"
        }
      ]
    }
    ...
  ]
...

設定例:

[semgrep]
  [[semgrep.ruleset]]
    [semgrep.ruleset.identifier]
      type = "semgrep_id"
      value = "gosec.G106-1
    ...

[$analyzer.ruleset.override] セクション

[$analyzer.ruleset.override] セクションでは、定義済みのルールの属性を上書きできます。

設定説明
descriptionイシューの詳細。
message(非推奨) イシューの説明。
nameルールの名前。
severityルールの重大度。有効なオプションは以下のとおり:Critical High,Medium,Low,Unknown,Info) です。
note
message はアナライザによって設定されますが、namedescription のために非推奨となりました。

設定例:

[semgrep]
  [[semgrep.ruleset]]
    [semgrep.ruleset.override]
      severity = "Critical"
      name = "Command injection"
    ...

[[$analyzer.passthrough]] セクション

note
現在、nodejs-scan およびsemgrep アナライザーのみでサポートされています。

[[$analyzer.passthrough]] セクションでは、アナライザーのカスタム設定を合成できます。このセクションは、1つのアナライザにつき最大20個まで定義できます。パススルーは_パススルー・チェーンに_Composer され、アナライザの定義済みルールを置き換える完全な設定に評価されます。

パススルーは順番に評価されます。チェーンの後半に記載されているパススルーの優先順位が高くなり、前のパススルーによって生成されたデータを上書きまたは追加できます (mode に依存)。これは、既存の設定を使用または変更する必要がある場合に便利です。

単一のパススルーによって生成されるデータ量は、1 MB に制限されています。

設定適用対象説明
type全て file,raw,git,url のいずれか。
target全てパススルー評価によって書き込まれるデータを格納するターゲット・ファイル。空の場合、ランダムなファイル名が使用されます。
mode全て overwrite の場合、target ファイルは上書きされます。append の場合、新しい内容がtarget ファイルに追加されます。git タイプはoverwrite. overwriteNET のみサポートしています。
reftype = "git"ブランチ、タグ、またはプルする SHA の名前をコンテナで指定します。
subdirtype = "git"Git リポジトリのサブディレクトリを設定ソースとして選択します。
value全て file,url,git タイプの場合、ファイルまたは Git リポジトリの場所を定義します。raw タイプの場合、インライン設定がコンテナに含まれます。
validator全てパススルーの評価後に、ターゲットファイルに対してバリデータ (xml,yaml,json,toml) を明示的に起動するために使用します。

パススルーの型

種類説明
fileGit リポジトリに存在するファイルを使用します。
raw設定をインラインで提供します。
gitリモートの Git リポジトリから設定を取り込みます。
urlHTTPを使って設定を取得します。
caution
YAML スニペットでraw パススルーを使う場合、sast-ruleset.toml ファイルのインデントをすべて空白にすることを推奨します。YAML の仕様ではタブよりもスペースが必須であり、インデントが適切に表現されないとアナライザーはカスタムルールセットの解析に失敗します。

使用例

SASTアナライザの定義済みルールを無効にします。

以下のカスタムルールセット設定では、以下のルールがレポートから除外されます:

  • semgrep semgrep_idgosec.G106-1 またはcwe322 のルール。
  • sobelow sobelow_rule_idsql_injection の規則。
  • flawfinder flawfinder_func_namememcpy の規則。
[semgrep]
  [[semgrep.ruleset]]
    disable = true
    [semgrep.ruleset.identifier]
      type = "semgrep_id"
      value = "gosec.G106-1"

  [[semgrep.ruleset]]
    disable = true
    [semgrep.ruleset.identifier]
      type = "cwe"
      value = "322"

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

[flawfinder]
  [[flawfinder.ruleset]]
    disable = true
    [flawfinder.ruleset.identifier]
      type = "flawfinder_func_name"
      value = "memcpy"

SASTアナライザの定義済みルールのオーバーライド

以下のカスタムルールセット設定では、semgrep で検出された脆弱性で、タイプがCWE で、値が322 の場合、深刻度がCritical に上書きされます。

[semgrep]
  [[semgrep.ruleset]]
    [semgrep.ruleset.identifier]
      type = "cwe"
      value = "322"
    [semgrep.ruleset.override]
      severity = "Critical"

の生のパススルーを使用して、カスタム設定を合成します。nodejs-scan

以下のカスタムルールセット設定により、nodejs-scan アナライザーの定義済みの動作がカスタム設定に置き換えられます。

valuenjsscan configフォーマットに従った構文が使用されます。

[nodejs-scan]
  description = "My 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
'''

のファイル・パススルーを使用してカスタム設定を合成します。semgrep

次のカスタムルールセット設定により、semgrep アナライザーの事前定義されたルールセットが、スキャン対象のリポジトリ内のmy-semgrep-rules.yaml というファイルに含まれるカスタムルールセットで置き換えられます。

# my-semgrep-rules.yml
---
rules:
- id: my-custom-rule
  pattern: print("Hello World")
  message: |
    Unauthorized use of Hello World.
  severity: ERROR
  languages:
  - python
[semgrep]
  description = "My custom ruleset for Semgrep"

  [[semgrep.passthrough]]
    type  = "file"
    value = "my-semgrep-rules.yml"

のパススルーチェーンを使用してカスタム設定を合成します。semgrep

以下のカスタム・ルールセット設定では、semgrep アナライザの定義済みルールセットが、4 つのパススルーのチェーンを評価することによって生成されるカスタム・ルールセットに置き換えられます。各パススルーは、コンテナ内の/sgrules ディレクトリに書き込まれるファイルを生成します。Gitリモートが応答しない場合に備えて、timeout 60秒が設定されています。

この例では、さまざまなパススルーのタイプを示します:

  • git 最初のブランチはmyrules Git リポジトリからdevelop ブランチを、2 番目のブランチはsast-rules リポジトリから97f7686 リビジョンを取得し、go サブディレクトリのファイルのみを対象とします。
    • sast-rules のエントリのほうが優先順位が高いのは、設定の後半に現れるからです。
    • 2つのチェックアウトの間でファイル名が衝突すると、sast-rules リポジトリのファイルがmyrules リポジトリのファイルを上書きします。
  • raw パススルーは、そのvalue/sgrules/insecure.yml に書き込みます。
  • URLでホストされている設定をフェッチし、それを/sgrules/gosec.yml に書き込むurl パススルー。

その後、Semgrepは/sgrules の下にある最終設定で起動されます。

[semgrep]
  description = "My custom ruleset for Semgrep"
  targetdir = "/sgrules"
  timeout = 60

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

  [[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"

チェーン内のパススルーモードの設定

チェイン内のパススルー間で発生するファイル名の衝突の処理方法を選択できます。デフォルトの動作は、同じ名前の既存のファイルを上書きすることですが、代わりにmode = append を選択すると、後のファイルの内容を前のファイルに追加することができます。

append モードは、fileurlraw パススルー・タイプにのみ使用できます。

次のカスタムルールセット設定では、2つのraw パススルーを使用して、/sgrules/my-rules.yml ファイルを繰り返し組み立て、それをルールセットとしてSemgrepに提供します。各パススルーはルールセットに1つのルールを追加します。最初のパススルーは、Semgrepルール構文に従って、トップレベルのrules オブジェクトを初期化します。

[semgrep]
  description = "My custom ruleset for Semgrep"
  targetdir = "/sgrules"
  validate = true

  [[semgrep.passthrough]]
    type  = "raw"
    target = "my-rules.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 = "my-rules.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
  metadata:
    cwe: "..."
  severity: "ERROR"
  languages:
    - "go"
"""
# /sgrules/my-rules.yml
rules:
- id: "insecure"
  patterns:
    - pattern: "func insecure() {...}"
  message: |
    Insecure function 'insecure' detected
  metadata:
    cwe: "..."
  severity: "ERROR"
  languages:
    - "go"
- id: "secret"
  patterns:
    - pattern-either:
        - pattern: '$MASK = "..."'
    - metavariable-regex:
        metavariable: "$MASK"
        regex: "(password|pass|passwd|pwd|secret|token)"
  message: |
    Use of hard-coded password
  metadata:
    cwe: "..."
  severity: "ERROR"
  languages:
    - "go"

非公開リモート設定の指定

以下の例では、SAST を有効にし、共有ルールセットカスタマイズファイルを使用します。ファイルは

  • グループアクセストークンを使用して、認証を必要とする非公開プロジェクトからダウンロードされます。
  • デフォルトのブランチではなく、特定の Git コミット SHA でチェックアウトした場合。

グループトークンに関連づけられたユーザー名を調べる方法についてはグループアクセストークンを参照ください。

include:
  - template: Security/SAST.gitlab-ci.yml

variables:
  SAST_RULESET_GIT_REFERENCE: "group_2504721_bot_7c9311ffb83f2850e794d478ccee36f5:glpat-1234567@gitlab.com/example-group/example-ruleset-project@c8ea7e3ff126987fb4819cc35f2310755511c2ab"