사용자 설정 규칙
- GitLab 13.5에서 도입되었습니다.
- GitLab 14.6에서는 passthrough chains의 지원을 확장하여
file
,git
, 및url
과 같은 추가적인 passthrough 유형을 포함했습니다.- GitLab 14.8에서 규칙 재정의를 지원하도록 활성화되었습니다.
- GitLab 16.2에서 모호한 passthrough 참조를 지정하는 기능이 활성화되었습니다.
저희의 SAST 분석기의 동작을 사용자 정의하려면 프로젝트에서 규칙 집합 구성 파일을 정의하세요. 두 종류의 사용자 정의가 있습니다:
-
프리디파인드 규칙의 동작을 수정합니다. 이에는 다음이 포함됩니다:
- 프리디파인드 규칙 비활성화. 모든 분석기에 사용 가능합니다.
- 프리디파인드 규칙 재정의. 모든 분석기에 사용 가능합니다.
- 파스트루스(passthroughs)를 사용하여 프리디파인드 규칙을 합성함. 파스트루스를 사용하여 사전에 정의된 규칙을 교체할 수 있습니다. 이는 nodejs-scan 및 semgrep에만 사용할 수 있습니다.
프리디파인드 규칙 비활성화
어떤 SAST 분석기의 프리디파인드 규칙을 비활성화할 수 있습니다.
규칙을 비활성화하면:
- 대부분의 분석기는 여전히 취약점을 스캔합니다. 스캔이 완료된 후 결과가 처리 단계에서 제거되어
gl-sast-report.json
artifact에 표시되지 않습니다. - 비활성화된 규칙의 결과는 파이프라인 보안 탭에 나타나지 않습니다.
- 기본 브랜치에서 비활성화된 규칙의 기존 결과는 취약점 보고서에서
No longer detected
로 표시됩니다.
Semgrep 기반 분석기는 비활성화된 규칙을 다르게 처리합니다:
- 성능을 개선하기 위해 Semgrep 기반 분석기는 비활성화된 규칙을 전혀 스캔하지 않습니다.
- Semgrep 기반 분석기에서 규칙을 비활성화하면 해당 규칙에 대한 기존 취약성 결과가
sast-ruleset.toml
파일을 기본 브랜치에 병합한 후 자동으로 해결됩니다.
사용자 정의 방법에 대한 정보는 구조(schema) 및 예제(examples) 섹션을 참조하세요.
프리디파인드 규칙 재정의
모든 SAST 분석기에 대해 프리디파인드 규칙의 특정 속성을 재정의할 수 있습니다. 이것은 SAST를 기존의 작업흐름이나 도구에 맞게 조정할 때 유용합니다. 예를 들어 조직 정책에 따라 취약성의 심각도를 재정의하거나, 취약점 보고서에 표시할 다른 메시지를 선택할 수 있습니다.
사용자 정의 방법에 대한 정보는 구조(schema) 및 예제(examples) 섹션을 참조하세요.
커스텀 구성 합성
특정 SAST 분석기의 사전에 정의된 규칙을 완전히 대체할 수 있습니다:
- nodejs-scan - 기본 njsscan 구성 파일을 대체할 수 있습니다.
- semgrep - GitLab-maintained ruleset을 대체할 수 있습니다.
파스트루스를 통해 사용자 정의를 제공하여 실행 시에 passthrough 체인을 구성하고 완전한 구성을 생성합니다. 그런 다음 기반 스캐너가 이 새로운 구성에 대해 실행됩니다.
다양한 passthrough 유형을 사용하여 리포지토리에 커밋된 파일을 사용하거나 규칙 집합 구성 파일 내에서 인라인으로 사용하는 등 다양한 방법으로 구성을 제공할 수 있습니다. 또한 체인의 후속 passthrough가 이전 구성을 덮어쓰거나 추가하는 방식을 선택할 수 있습니다.
사용자 정의 방법에 대한 정보는 구조(schema) 및 예제(examples) 섹션을 참조하세요.
구성 파일 만들기
규칙 집합 구성 파일을 만들려면:
- 프로젝트의 루트에
.gitlab
디렉토리를 생성하거나, 이미 있는 경우 건너뜁니다. -
.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"
고급 사용법에 대한 예시는 비공개 원격 구성 파일 지정 예시를 참조하세요.
원격 구성 파일 문제 해결
원격 구성 파일이 사용자 정의를 올바르게 적용하지 않는 경우 원인은 다음과 같을 수 있습니다.
- 귀하의 저장소에 로컬
.gitlab/sast-ruleset.toml
파일이 있습니다.- 로컬 파일이 있으면 원격 구성이 변수로 설정되어 있더라도 로컬 파일이 사용됩니다.
- 이 논리의 변경은 issue 414732에서 고려됩니다.
- 인증에 문제가 있습니다.
- 이 문제가 원인인지 확인하려면 인증이 필요하지 않은 저장소 위치에서 구성 파일을 참조해 보세요.
스키마
최상위 섹션
최상위 섹션에는 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
경고: 비밀을 누설하는 위험을 줄이려면 이 기능을 주의해서 사용하세요.
아래 예시에서는 $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
을 확인하여 type
및 value
의 올바른 값을 찾을 수 있습니다.
이 파일은 분석기의 CI 작업에서 작업 artifact로 다운로드할 수 있습니다.
예를 들어, 아래 스니펫은 세 가지 식별자가 있는 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 )
|
참고:
message
는 분석기에 의해 생성되지만, name
및 description
을 선호하는 바에 따라 사용 중지되었습니다.
구성 예시:
[semgrep]
[[semgrep.ruleset]]
[semgrep.ruleset.override]
severity = "Critical"
name = "Command injection"
...
[[$analyzer.passthrough]]
섹션
참고:
현재 nodejs-scan
및 semgrep
분석기에서만 지원됩니다.
[[$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_id
가gosec.G106-1
또는cwe
가322
인 경우. -
sobelow
규칙 중sobelow_rule_id
가sql_injection
인 경우. -
flawfinder
규칙 중flawfinder_func_name
이memcpy
인 경우.
[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.yml
에value
를 작성합니다. -
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"