사용자 정의 규칙 세트
- GitLab 16.2에서 모호한 passthrough refs를 지정하는 지원(이곳)을 활성화했습니다.
당사의 SAST 분석기의 동작을 규칙 세트 구성 파일을 정의하여 사용자 정의할 수 있습니다. 두 가지 유형의 사용자 정의가 있습니다.
-
사전 정의된 규칙의 동작 수정. 이에는 다음이 포함됩니다:
- 사전 정의된 규칙 비활성화. 모든 분석기에서 사용 가능.
- 사전 정의된 규칙 재정의. 모든 분석기에서 사용 가능.
- passthroughs를 사용하여 사전 정의된 규칙 교체 nodejs-scan 및 semgrep에만 사용 가능한 사용자 정의입니다.
사전 정의된 규칙 비활성화
모든 SAST 분석기의 사전 정의된 규칙을 비활성화할 수 있습니다.
규칙을 비활성화하는 경우:
- 대부분의 분석기는 여전히 취약점을 스캔합니다. 스캔이 완료된 후 결과는 처리 단계에서 제거되어
gl-sast-report.json
아티팩트에 표시되지 않습니다. - 비활성화된 규칙에 대한 결과는 파이프라인 보안 탭에 표시되지 않습니다.
- 기본 브랜치에서 비활성화된 규칙에 대한 기존 결과는 취약성 보고서에서
더 이상 감지되지 않음
으로 표시됩니다.
Semgrep 기반 분석기는 비활성화된 규칙을 다르게 처리합니다.:
- 성능을 향상시키기 위해 Semgrep 기반 분석기는 비활성화된 규칙을 아예 스캔하지 않습니다.
- Semgrep 기반 분석기에서 규칙을 비활성화하면 해당 규칙의 기존 취약성 결과가
sast-ruleset.toml
파일을 기본 브랜치로 Merge한 후에 자동으로 해결됩니다.
이 동작을 구성하는 방법에 대한 정보는 스키마 및 예제 섹션을 참조하세요.
사전 정의된 규칙 재정의
모든 SAST 분석기의 사전 정의된 규칙의 특정 속성을 재정의할 수 있습니다. 이것은 SAST를 기존의 워크플로이나 도구에 맞게 조정할 때 유용합니다. 예를 들어, 조직 정책에 따라 취약점의 심각도를 재정의하거나, 취약점 보고서에 표시할 다른 메시지를 선택할 수 있습니다.
이 동작을 구성하는 방법에 대한 정보는 스키마 및 예제 섹션을 참조하세요.
사용자 정의 구성 생성
일부 SAST 분석기의 사전 정의된 규칙을 완전히 교체할 수 있습니다:
- nodejs-scan - 기본 njsscan configuration file을 본인의 파일로 교체할 수 있습니다.
- semgrep - GitLab 유지 관리 ruleset을 본인의 것으로 교체할 수 있습니다.
새로운 구성을 생성하기 위해 passthroughs를 통해 사용자 정의를 제공하고, 이를 실행시에 passthrough chain으로 결합하여 완전한 구성을 생성합니다. 그런 다음 기반이 되는 스캐너가 이 새로운 구성에 따라 실행됩니다.
여러 가지 passthrough 유형을 사용하여 파일로 커밋하거나 규칙 세트 구성 파일에 인라인으로 사용하는 등 다양한 방법으로 구성을 제공할 수 있으며, 체인에서 이후 passthroughs가 이전 구성을 덮어씌울지 또는 추가할지 선택할 수 있습니다.
이 동작을 구성하는 방법에 대한 정보는 스키마 및 예제 섹션을 참조하세요.
구성 파일 생성
규칙 세트 구성 파일을 만들려면 다음 단계를 따르세요:
- 프로젝트의 루트에
.gitlab
디렉터리를 만듭니다(이미 있다면 건너뜁니다). -
.gitlab
디렉터리에sast-ruleset.toml
이라는 파일을 만듭니다.
원격 구성 파일 지정
- 16.1에서 소개되었습니다.
CI/CD 변수를 설정하여 현재 리포지터리 외부에 저장된 규칙 세트 구성 파일을 사용할 수 있습니다. 이를 통해 여러 프로젝트에 동일한 규칙을 적용할 수 있습니다.
SAST_RULESET_GIT_REFERENCE
변수는 프로젝트 URI, 선택적 인증 및 선택적 Git SHA를 지정하는 Git URLs와 유사한 형식을 사용합니다. 이 변수는 다음 형식을 사용합니다:
[<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 분석기 디렉터리에서 정의된 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
아래 예는$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": "엔터티 인증없는 키 교환",
"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 ) 중 하나의 유효한 옵션입니다
|
구성 예:
[semgrep]
[[semgrep.ruleset]]
[semgrep.ruleset.override]
severity = "Critical"
name = "Command injection"
...
[[$analyzer.passthrough]]
섹션
nodejs-scan
및 semgrep
분석기에서만 지원됩니다.[[$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 , url 및git 유형의 경우 파일 또는 git 리포지터리의 위치를 정의합니다. raw 유형의 경우 인라인 구성을 포함합니다.
|
validator
| 모든 | passthrough의 평가 후 대상 파일에서 명시적으로 유효성 검사기 (xml ,yaml ,json ,toml )를 호출하는 데 사용됩니다.
|
Passthrough 유형
유형 | 설명 |
---|---|
file
| Git 리포지터리에있는 파일 사용 |
raw
| 인라인으로 구성 제공 |
git
| 원격 Git 리포지터리에서 구성을 가져옵니다. |
url
| HTTP를 사용하여 구성을 가져옵니다. |
raw
passthrough를 사용 할 때는 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 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"