사용자 정의 규칙 세트

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 파일을 기본 브랜치로 Merge한 후에 자동으로 해결됩니다.

이 동작에 대한 구성 방법에 대한 정보는 스키마예제 섹션을 참조하세요.

미리 정의된 규칙 재정의

모든 SAST 분석기에서 미리 정의된 규칙의 특정 속성을 재정의할 수 있습니다. 이는 SAST를 기존의 워크플로우나 도구에 적응시킬 때 유용합니다. 예를 들어, 조직 정책에 따라 취약점의 심각도를 재정의하거나 취약성 보고서에 표시할 다른 메시지를 선택할 수 있습니다.

이 동작에 대한 구성 방법에 대한 정보는 스키마예제 섹션을 참조하세요.

사용자 정의 구성 합성

일부 SAST 분석기의 미리 정의된 규칙을 완전히 교체할 수 있습니다:

사용자 정의는 passthroughs를 통해 제공되며, 실행 시 passthrough 체인으로 구성되어 완전한 구성을 생성하고 평가됩니다. 그런 다음 기본 스캐너가이 새 구성에 대해 실행됩니다.

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

이 동작에 대한 구성 방법에 대한 정보는 스키마예제 섹션을 참조하세요.

구성 파일 생성

규칙 세트 구성 파일을 생성하려면:

  1. 프로젝트의 루트에 .gitlab 디렉터리를 생성합니다(존재하지 않는 경우).
  2. .gitlab 디렉터리에 sast-ruleset.toml이라는 파일을 생성합니다.

원격 구성 파일 지정

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

현재 리포지터리 외부에 저장된 규칙 세트 구성 파일을 사용하려면 CI/CD 변수를 설정할 수 있습니다. 이를 통해 동일한 규칙을 여러 프로젝트에 적용할 수 있습니다.

SAST_RULESET_GIT_REFERENCE 변수는 프로젝트 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"

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

원격 구성 파일 문제 해결

원격 구성 파일이 사용자 정의를 올바르게 적용하지 않는 것으로 보일 때 원인은 다음과 같을 수 있습니다:

  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, json, toml 내용에 대해 작동합니다. 올바른 유효성 검사 도구는 [[$analyzer.passthrough]] 섹션의 target 매개변수에서 사용된 확장자를 기반으로 식별됩니다. (기본값: false)
timeout 통과 타임아웃되기 전에 통과 체인을 평가하는 데 소요되는 최대 시간. 타임아웃은 300초를 초과할 수 없습니다. (기본값: 60)

interpolate

caution
비밀이 누출될 위험을 줄이기 위해이 기능을 신중하게 사용하십시오.

아래 예시는 $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 미리 정의된 규칙에서 사용되는 식별자의 값

귀하는 분석기의 CI 작업에서 생성된 gl-sast-report.json을 보고 typevalue 값을 확인하여 이 섹션에 제공해야 합니다. 이 파일은 분석기의 작업 아티팩트로 다운로드할 수 있습니다.

예를 들어 아래 스니펫은 셋세마 섹션에 제공해야 하는 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)
note
message는 분석기에서 생성되지만 이제 사용 중단되었습니다 namedescription을 선호합니다.

구성 예시:

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

[[$analyzer.passthrough]] 섹션

note
현재 nodejs-scansemgrep 분석기만 지원합니다.

[[$analyzer.passthrough]] 섹션을 사용하면 분석기에 대한 사용자 정의 구성을 합성할 수 있습니다. 각 분석기당 최대 20개의 이러한 섹션을 정의할 수 있습니다. Passthrough는 사전에 정의된 분석기의 규칙을 대체하는 완전한 구성으로 평가되며 _passthrough 연쇄_로 구성됩니다.

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

단일 Passthrough에 의해 생성된 데이터의 양은 1MB로 제한됩니다.

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

Passthrough 유형

유형 설명
file Git 리포지터리에 있는 파일을 사용합니다.
raw 구성을 인라인으로 제공합니다.
git 원격 Git 리포지터리에서 구성을 가져옵니다.
url HTTP를 사용하여 구성을 가져옵니다.
caution
YAML 조각으로 raw passthrough를 사용할 때, sast-ruleset.toml 파일의 모든 들여쓰기를 공백으로 포맷하는 것이 좋습니다. YAML 사양은 탭보다 공백을 필요로 하며, 들여쓰기가 그에 따라 표현되지 않으면 분석기가 사용자 정의 규칙을 구문 분석하지 못할 수 있습니다.

예시

SAST 분석기의 사전 정의된 규칙 비활성화

다음 사용자 정의 규칙 구성으로 다음과 같은 규칙이 보고서에서 제외됩니다:

  • semgrepsemgrep_idgosec.G106-1 또는 cwe322인 규칙.
  • sobelowsobelow_rule_idsql_injection인 규칙.
  • flawfinderflawfinder_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을 위한 raw passthrough를 사용하여 사용자 정의 구성 합성

다음 사용자 정의 규칙 구성으로,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 리포지터리에서 revision 97f7686를 풀링하며 go 하위 디렉터리에 있는 파일만을 고려합니다.
    • sast-rules 항목은 설정을 덮어씁니다. 왜냐하면 설정이 뒤에 나타나기 때문입니다.
    • 두 체크아웃 사이에 파일명 충돌이 있는 경우, sast-rules 리포지터리의 파일이 myrules 리포지터리의 파일을 덮어씁니다.
  • raw 통과는 value/sgrules/insecure.yml에 씁니다.
  • url 통과는 URL에서 호스팅되는 구성을 가져와 /sgrules/gosec.yml에 씁니다.

그 후, 마지막 구성을 사용하여 /sgrules 아래에 위치한 Semgrep를 호출합니다.

[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 function이 감지됨
  metadata:
    cwe: "CWE-200: 미인가된 사용자에게 민감한 정보 노출"
  severity: "ERROR"
  languages:
    - "go"
"""
  
  [[semgrep.passthrough]]
    type  = "url"
    value = "https://semgrep.dev/c/p/gosec"
    target = "gosec.yml"

연결된 통과의 모드를 구성하십시오

연결된 통과들 간의 파일 이름 충돌을 어떻게 처리할지 선택할 수 있습니다. 기본 동작은 동일한 이름의 기존 파일을 덮어쓰지만, 대신 mode = append를 선택하여 이후 파일의 내용을 이전 파일에 추가할 수 있습니다.

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

다음 사용자 정의 규칙 집합 구성에서, 두 개의 raw 통과가 사용되어 반복적으로 /sgrules/my-rules.yml 파일이 구성되며 이 파일이 Semgrep에 규칙집합으로 제공됩니다. 각 통과는 규칙을 한 개씩 추가합니다. 첫 번째 통과는 Semgrep 규칙 구문에 따라 최상위 rules 객체를 초기화합니다.

[semgrep]
  description = "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' 감지됨
  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: |
    하드 코딩된 비밀번호 사용
  metadata:
    cwe: "..."
  severity: "ERROR"
  languages:
    - "go"
"""
# /sgrules/my-rules.yml
rules:
- id: "insecure"
  patterns:
    - pattern: "func insecure() {...}"
  message: |
    Insecure function 'insecure' 감지됨
  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: |
    하드 코딩된 비밀번호 사용
  metadata:
    cwe: "..."
  severity: "ERROR"
  languages:
    - "go"

개인 원격 구성 지정

다음 예제는 SAST를 활성화하고 공유된 규칙 집합 사용자 정의 파일을 사용합니다. 해당 파일은 다음과 같습니다.

  • 그룹 액세스 토큰을 사용하여 인증이 필요한 비공개 프로젝트에서 다운로드되며, 이는 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"