사용자 정의 규칙 세트

Tier: Ultimate Offering: GitLab.com, Self-Managed, GitLab Dedicated
  • GitLab 16.2에서 모호한 passthrough refs를 지정하는 지원(이곳)을 활성화했습니다.

당사의 SAST 분석기의 동작을 규칙 세트 구성 파일을 정의하여 사용자 정의할 수 있습니다. 두 가지 유형의 사용자 정의가 있습니다.

사전 정의된 규칙 비활성화

모든 SAST 분석기의 사전 정의된 규칙을 비활성화할 수 있습니다.

규칙을 비활성화하는 경우:

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

  • 성능을 향상시키기 위해 Semgrep 기반 분석기는 비활성화된 규칙을 아예 스캔하지 않습니다.
  • Semgrep 기반 분석기에서 규칙을 비활성화하면 해당 규칙의 기존 취약성 결과가 sast-ruleset.toml 파일을 기본 브랜치로 Merge한 후에 자동으로 해결됩니다.

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

사전 정의된 규칙 재정의

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

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

사용자 정의 구성 생성

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

새로운 구성을 생성하기 위해 passthroughs를 통해 사용자 정의를 제공하고, 이를 실행시에 passthrough chain으로 결합하여 완전한 구성을 생성합니다. 그런 다음 기반이 되는 스캐너가 이 새로운 구성에 따라 실행됩니다.

여러 가지 passthrough 유형을 사용하여 파일로 커밋하거나 규칙 세트 구성 파일에 인라인으로 사용하는 등 다양한 방법으로 구성을 제공할 수 있으며, 체인에서 이후 passthroughs가 이전 구성을 덮어씌울지 또는 추가할지 선택할 수 있습니다.

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

구성 파일 생성

규칙 세트 구성 파일을 만들려면 다음 단계를 따르세요:

  1. 프로젝트의 루트에 .gitlab 디렉터리를 만듭니다(이미 있다면 건너뜁니다).
  2. .gitlab 디렉터리에 sast-ruleset.toml이라는 파일을 만듭니다.

원격 구성 파일 지정

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

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

[<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 분석기 디렉터리에서 정의된 snake-case 이름을 따르는 분석기에 대한 구성 섹션을 선언합니다.

구성 예시:

[semgrep]
...

기존 규칙을 수정하고 사용자 정의 규칙 세트를 합성하는 구성 섹션을 생성하지 않도록 주의하세요.

[$analyzer] 구성 섹션

[$analyzer] 섹션을 통해 분석기의 동작을 사용자 정의할 수 있습니다. 유효한 속성들은 구성하는 유형에 따라 다릅니다.

설정 적용 대상 설명
[[$analyzer.ruleset]] 사전 정의된 규칙 기존 규칙을 수정하는 섹션을 정의합니다.
interpolate 모든 true로 설정하면 구성의 환경 변수를 $VAR를 사용하여 평가할 수 있습니다. 이 기능을 사용할 때 비밀이나 토큰이 누출되지 않도록 주의하세요. (기본값: false)
description Passthroughs 사용자 정의 규칙 세트에 대한 설명입니다.
targetdir Passthroughs 최종 구성이 보존될 디렉터리입니다. 비어 있을 경우 무작위 이름의 디렉터리가 생성됩니다. 디렉터리에는 최대 100MB의 파일이 들어갈 수 있습니다.
validate Passthroughs 각 passthrough의 내용을 유효성 검사합니다. 유효성 검사는 yaml, xml, json, toml 내용에 대해 작동합니다. 올바른 유효성 검사기는 [[$analyzer.passthrough]] 섹션의 target 매개변수에서 사용한 확장자에 따라 식별됩니다. (기본값: false)
timeout Passthroughs 시간 초과 전에 passthrough 체인을 평가하는 데 드는 최대 시간입니다. 시간 초과는 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 사전 정의 규칙에서 사용하는 식별자 값

분석기에서 생성 된 gl-sast-report.json을 보고 식별류 typevalue에 대한 올바른 값을 찾을 수 있습니다. 분석기의 CI 작업에서 작업 artifact로이 파일을 다운로드 할 수 있습니다.

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

...
  "vulnerabilities": [
    {
      "id": "7331a4b7093875f6eb9f6eb1755b30cc792e9fb3a08c9ce673fb0d2207d7c9c9",
      "category": "sast",
      "message": "엔터티 인증없는 키 교환",
      "description": "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 개의 이러한 섹션을 정의 할 수 있습니다. Passthroughs는 _passthrough chain_으로 합성되어 분석기의 사전 정의 규칙을 대체하는 완전한 구성으로 평가됩니다.

Passthroughs는 순서대로 평가됩니다. 체인에 나열 된 Passthroughs는 더 높은 우선 순위를 갖습니다. 이전 Passthroughs에 의해 생성 된 데이터를 덮어 쓰거나 추가 할 수 있습니다 (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, urlgit 유형의 경우 파일 또는 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 분석기의 사전 정의 규칙 비활성화

다음 사용자 정의 규칙 집합 구성으로보고서에서 다음 규칙이 제외됩니다.

  • 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 config format을 따릅니다.

[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에 대한 파일 패스스루를 사용한 사용자 정의 구성 합성

다음 사용자 지정 규칙 집합 구성을 사용하여 스캔 중인 리포지터리에 있는 my-semgrep-rules.yaml이라는 파일에 포함된 사용자 정의 규칙집합으로 semgrep 분석기의 사전 정의된 규칙집합이 대체됩니다.

# 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 원격 리포지터리가 응답하지 않는 경우를 대비하여 timeout이 60초로 설정됩니다.

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

  • 두 개의 git 패스스루를 사용하여 체인으로 평가되는 사용자 정의 규칙집합의 기본 방식을 nodejs-scan 분석기의 사전 정의 동작에 포함할 수 있습니다.

  • sast-rules 항목이 후순위에 있으므로 sast-rules 항목이 구성에서 나중에 나타나고 있기 때문에 sast-rules 항목이 myrules 리포지터리보다 우선합니다. 두 체크아웃 사이에 파일 이름 충돌이 있는 경우 sast-rules 리포지터리가 myrules 리포지터리의 파일을 덮어씁니다.

  • 원래값(raw)을 사용하여 /sgrules/insecure.yml에 값을 쓰는 raw 패스스루
  • URL에서 호스팅된 구성을 가져와 /sgrules/gosec.yml에 쓰는 url 패스스루

이후, 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: |
    무단으로 사용된 불안전한 함수를 감지했습니다.
  metadata:
    cwe: "CWE-200: 미인가된 사용자에 대한 민감한 정보 노출"
  severity: "ERROR"
  languages:
    - "go"
"""
  
  [[semgrep.passthrough]]
    type  = "url"
    value = "https://semgrep.dev/c/p/gosec"
    target = "gosec.yml"

체인 내의 패스스루에 대한 모드 구성

체인 내의 패스스루 간에 발생하는 파일 이름 충돌을 처리하는 방법을 선택할 수 있습니다. 기본 동작은 동일한 이름을 가진 기존 파일을 덮어쓰지만 mode = append 대신 mode를 선택하여 나중에 있는 파일의 내용을 이전 것에 추가할 수 있습니다.

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'가 감지되었습니다.
  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'가 감지되었습니다.
  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"