사용자 설정 규칙

Tier: Ultimate Offering: GitLab.com, Self-managed, GitLab Dedicated
  • GitLab 13.5에서 도입되었습니다.
  • GitLab 14.6에서는 passthrough chains의 지원을 확장하여 file, git, 및 url과 같은 추가적인 passthrough 유형을 포함했습니다.
  • GitLab 14.8에서 규칙 재정의를 지원하도록 활성화되었습니다.
  • GitLab 16.2에서 모호한 passthrough 참조를 지정하는 기능이 활성화되었습니다.

저희의 SAST 분석기의 동작을 사용자 정의하려면 프로젝트에서 규칙 집합 구성 파일을 정의하세요. 두 종류의 사용자 정의가 있습니다:

프리디파인드 규칙 비활성화

어떤 SAST 분석기의 프리디파인드 규칙을 비활성화할 수 있습니다.

규칙을 비활성화하면:

Semgrep 기반 분석기는 비활성화된 규칙을 다르게 처리합니다:

  • 성능을 개선하기 위해 Semgrep 기반 분석기는 비활성화된 규칙을 전혀 스캔하지 않습니다.
  • Semgrep 기반 분석기에서 규칙을 비활성화하면 해당 규칙에 대한 기존 취약성 결과가 sast-ruleset.toml 파일을 기본 브랜치에 병합한 후 자동으로 해결됩니다.

사용자 정의 방법에 대한 정보는 구조(schema)예제(examples) 섹션을 참조하세요.

프리디파인드 규칙 재정의

모든 SAST 분석기에 대해 프리디파인드 규칙의 특정 속성을 재정의할 수 있습니다. 이것은 SAST를 기존의 작업흐름이나 도구에 맞게 조정할 때 유용합니다. 예를 들어 조직 정책에 따라 취약성의 심각도를 재정의하거나, 취약점 보고서에 표시할 다른 메시지를 선택할 수 있습니다.

사용자 정의 방법에 대한 정보는 구조(schema)예제(examples) 섹션을 참조하세요.

커스텀 구성 합성

특정 SAST 분석기의 사전에 정의된 규칙을 완전히 대체할 수 있습니다:

파스트루스를 통해 사용자 정의를 제공하여 실행 시에 passthrough 체인을 구성하고 완전한 구성을 생성합니다. 그런 다음 기반 스캐너가 이 새로운 구성에 대해 실행됩니다.

다양한 passthrough 유형을 사용하여 리포지토리에 커밋된 파일을 사용하거나 규칙 집합 구성 파일 내에서 인라인으로 사용하는 등 다양한 방법으로 구성을 제공할 수 있습니다. 또한 체인의 후속 passthrough가 이전 구성을 덮어쓰거나 추가하는 방식을 선택할 수 있습니다.

사용자 정의 방법에 대한 정보는 구조(schema)예제(examples) 섹션을 참조하세요.

구성 파일 만들기

규칙 집합 구성 파일을 만들려면:

  1. 프로젝트의 루트에 .gitlab 디렉토리를 생성하거나, 이미 있는 경우 건너뜁니다.
  2. .gitlab 디렉토리에 sast-ruleset.toml이라는 파일을 생성합니다.

원격 구성 파일 지정

  • 16.1에서 도입되었습니다.

현재 저장소 외부에 저장된 규칙 세트 구성 파일을 사용하도록 CI/CD 변수를 설정할 수 있습니다. 이를 통해 여러 프로젝트에 동일한 규칙을 적용하는 데 도움을 줄 수 있습니다.

SAST_RULESET_GIT_REFERENCE 변수는 프로젝트 URI, 선택적 인증 및 선택적 Git SHA를 지정하기 위한 Git URL과 유사한 형식을 사용합니다. 이 변수는 다음 형식을 사용합니다.

[<AUTH_USER>[:<AUTH_PASSWORD>]@]<PROJECT_PATH>[@<GIT_SHA>]

참고: 프로젝트에 .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"

고급 사용법에 대한 예시는 비공개 원격 구성 파일 지정 예시를 참조하세요.

원격 구성 파일 문제 해결

원격 구성 파일이 사용자 정의를 올바르게 적용하지 않는 경우 원인은 다음과 같을 수 있습니다.

  1. 귀하의 저장소에 로컬 .gitlab/sast-ruleset.toml 파일이 있습니다.
    • 로컬 파일이 있으면 원격 구성이 변수로 설정되어 있더라도 로컬 파일이 사용됩니다.
    • 이 논리의 변경은 issue 414732에서 고려됩니다.
  2. 인증에 문제가 있습니다.
    • 이 문제가 원인인지 확인하려면 인증이 필요하지 않은 저장소 위치에서 구성 파일을 참조해 보세요.

스키마

최상위 섹션

최상위 섹션에는 TOML 테이블로 정의된 하나 이상의 _구성 섹션_이 포함됩니다.

설정 설명
[$analyzer] 분석기에 대한 구성 섹션을 선언합니다. 이름은 SAST analyzers 목록에서 정의된 스네이크 케이스 이름을 따릅니다.

구성 예시:

[semgrep]
...

기존 규칙을 수정하고 사용자 지정 규칙 세트를 합성하는 구성 섹션을 만드는 것은 피하세요, 후자는 미리 정의된 규칙을 완전히 대체합니다.

[$analyzer] 구성 섹션

[$analyzer] 섹션을 사용하면 분석기의 동작을 사용자 지정할 수 있습니다. 유효한 속성은 구성하는 종류에 따라 달라집니다.

설정 적용 대상 설명
[[$analyzer.ruleset]] 미리 정의된 규칙 기존 규칙에 대한 수정을 정의합니다.
interpolate 모두 true로 설정하면 구성에서 환경 변수를 평가할 수 있습니다. 이 기능을 사용할 때에는 비밀이나 토큰이 노출되지 않도록 주의하세요. (기본값: false)
description 패스스루 사용자 지정 규칙 세트에 대한 설명입니다.
targetdir 패스스루 최종 구성이 지속되어야 하는 디렉터리입니다. 비어 있으면 랜덤한 이름의 디렉터리가 생성됩니다. 디렉터리에는 최대 100MB의 파일을 포함할 수 있습니다.
validate 패스스루 true로 설정하면 각 패스스루의 내용이 유효성을 검사됩니다. 유효성 검사는 yaml, xml, jsontoml 내용에 대해 작동합니다. 적절한 유효성 검사기는 [[$analyzer.passthrough]] 섹션의 target 매개변수에 사용된 확장자에 따라 식별됩니다. (기본값: false)
timeout 패스스루 타임아웃하기 전에 패스스루 체인을 평가하는 데 소요되는 최대 시간입니다. 타임아웃은 300초를 초과할 수 없습니다. (기본값: 60)

interpolate

경고: 비밀을 누설하는 위험을 줄이려면 이 기능을 주의해서 사용하세요.

아래 예시에서는 $GITURL 환경 변수를 사용하여 개인 저장소에 액세스하는 구성을 보여줍니다. 변수에는 사용자 이름 및 토큰(예: https://user:token@url)이 포함되어 있어서 이를 구성 파일에 명시적으로 저장하지 않습니다.

[semgrep]
  description = "내 개인 Semgrep 규칙 세트"
  interpolate = true

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

[[$analyzer.ruleset]] 섹션

[[$analyzer.ruleset]] 섹션은 단일 미리 정의된 규칙을 대상으로 하고 수정합니다. 분석기 당 하나 이상의 이러한 섹션을 정의할 수 있습니다.

설정 설명
disable 규칙을 비활성화해야 하는지 여부. (기본값: false)
[$analyzer.ruleset.identifier] 수정할 미리 정의된 규칙을 선택합니다.
[$analyzer.ruleset.override] 규칙의 재정의를 정의합니다.

구성 예시:

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

[$analyzer.ruleset.identifier] 섹션

[$analyzer.ruleset.identifier] 섹션은 수정하려는 미리 정의된 규칙의 식별자를 정의합니다.

설정 설명
type 미리 정의된 규칙에서 사용되는 식별자의 유형
value 미리 정의된 규칙에서 사용되는 식별자의 값

분석기에서 생성된 gl-sast-report.json을 확인하여 typevalue의 올바른 값을 찾을 수 있습니다. 이 파일은 분석기의 CI 작업에서 작업 artifact로 다운로드할 수 있습니다.

예를 들어, 아래 스니펫은 세 가지 식별자가 있는 semgrep 규칙에서 찾은 결과를 보여줍니다. JSON 객체의 typevalue 키는 이 섹션에서 제공해야 하는 값과 일치합니다.

...
  "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)

참고: message는 분석기에 의해 생성되지만, namedescription을 선호하는 바에 따라 사용 중지되었습니다.

구성 예시:

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

[[$analyzer.passthrough]] 섹션

참고: 현재 nodejs-scansemgrep 분석기에서만 지원됩니다.

[[$analyzer.passthrough]] 섹션을 사용하여 분석기에 대한 사용자 정의 구성을 합성할 수 있습니다. 분석기 당 최대 20개의 이러한 섹션을 정의할 수 있습니다. 패스스루는 완전한 구성으로 평가되는 _패스스루 체인_으로 결합되며, 분석기의 미리 정의된 규칙을 대체합니다.

패스스루는 순서대로 평가됩니다. 체인에 나열된 나중의 패스스루가 더 높은 우선순위를 갖고 이전의 패스스루에 의해 생성된 데이터를 덮어쓰거나 추가할 수 있습니다(mode에 따라). 이는 기존 구성을 사용하거나 수정해야 하는 경우 유용합니다.

단일 패스스루에서 생성되는 데이터의 양은 1MB로 제한됩니다.

설정 적용 대상 설명
type All file, raw, git, 또는 url 중 하나
target All 패스스루 평가에 의해 작성된 데이터를 포함할 대상 파일. 비어 있으면 무작위 파일 이름이 사용됩니다.
mode All overwrite의 경우 target 파일이 덮어쓰입니다. append의 경우 새로운 내용이 target 파일에 추가됩니다. git 유형은 overwrite만 지원합니다. (기본값: overwrite)
ref type = "git" 가져올 브랜치, 태그 또는 SHA의 이름을 포함합니다.
subdir type = "git" Git 저장소의 하위 디렉토리를 구성 소스로 선택하는 데 사용됩니다.
value All file, url, 및 git 유형의 경우 파일 또는 Git 저장소의 위치를 정의합니다. raw 유형의 경우 인라인 구성을 포함합니다.
validator All 패스스루 평가 후 대상 파일에 명시적으로 유효성 검사기(xml, yaml, json, toml)가 호출됩니다.

패스스루 유형

유형 설명
file 저장소에 있는 파일을 사용합니다.
raw 구성을 인라인으로 제공합니다.
git 원격 Git 저장소에서 구성을 가져옵니다.
url HTTP를 사용하여 구성을 가져옵니다.

경고: raw 패스스루를 사용하여 YAML 스니펫을 사용할 때, 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 분석기의 미리 정의된 동작이 사용자 정의 구성으로 대체됩니다.

value에 사용된 구문은 njsscan 구성 형식을 따릅니다.

[nodejs-scan]
  description = "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: |
    Hello World의 무단 사용.
  severity: ERROR
  languages:
  - python
[semgrep]
  description = "Semgrep에 대한 내 사용자 정의 규칙 세트"

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

semgrep에 대한 패스스루 체인 사용하여 사용자 정의 구성 합성

다음 사용자 정의 규칙 세트 구성으로, semgrep 분석기의 미리 정의된 규칙 세트가 네 가지 패스스루를 평가하여 생성된 사용자 정의 규칙 세트로 대체됩니다. 각 패스스루는 컨테이너 내의 /sgrules 디렉터리에 작성됩니다. Git 원격이 응답하지 않을 경우, 60초의 timeout가 설정됩니다.

이 예에서 다양한 패스스루 유형을 보여줍니다:

  • git 패스스루 두 개는 첫 번째가 myrules Git 저장소의 develop 브랜치를 풀고 두 번째가 sast-rules 저장소의 97f7686 리비전을 풀며 go 하위 디렉터리의 파일만 고려합니다.
    • sast-rules 항목은 구성이 후에 나타나기 때문에 우선순위가 더 높습니다.
    • 두 체크아웃 사이에 파일 이름 충돌이 있는 경우, sast-rules 저장소의 파일이 myrules 저장소의 파일을 덮어씁니다.
  • raw 패스스루는 /sgrules/insecure.ymlvalue를 작성합니다.
  • url 패스스루는 URL에 호스팅된 구성을 가져와 /sgrules/gosec.yml에 작성합니다.

이후에 Semgrep은 /sgrules에 위치한 최종 구성을 사용하여 호출됩니다.

[semgrep]
  description = "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 함수 감지됨
  metadata:
    cwe: "CWE-200: 민감한 정보를 무단 사용자에게 노출"
  severity: "ERROR"
  languages:
    - "go"
"""

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

체인 내에서 passthrough의 모드 구성

체인 내에서 발생하는 파일 이름 충돌을 어떻게 처리할지 선택할 수 있습니다. 기본 동작은 동일한 이름의 기존 파일을 덮어쓰는 것이지만, mode = append를 선택하여 나중 파일의 내용을 이전 파일에 추가하는 것으로 대체할 수 있습니다.

append 모드는 file, url, raw passthrough 유형에만 사용할 수 있습니다.

다음 사용자 정의 ruleset 구성에서 /sgrules/my-rules.yml 파일을 반복적으로 구성하기 위해 두 번의 raw passthrough가 사용되며, 이후에 해당 파일은 Semgrep에 ruleset으로 제공됩니다. 각 passthrough는 ruleset에 하나의 rule을 추가합니다. 첫 번째 passthrough는 Semgrep rule syntax에 따라 최상위 rules 오브젝트를 초기화하는 역할을 합니다.

[semgrep]
  description = "Semgrep를 위한 내 사용자 정의 ruleset"
  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를 활성화하고, 공유 ruleset 사용자 정의 파일을 사용합니다. 해당 파일은 다음과 같습니다:

  • CI 변수 내에 안전하게 저장된 그룹 액세스 토큰을 사용하여 인증이 필요한 비공개 프로젝트에서 다운로드됩니다.
  • 기본 브랜치 대신 특정한 Git 커밋 SHA에서 확인됩니다.

그룹 액세스 토큰에서 그룹 토큰과 관련된 사용자 이름을 찾는 방법은 참조하세요.

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

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