동작을 위한 의존성 분석
GitLab v19.5Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated
요약
Libbehave는 머지 리퀘스트 파이프라인에서 의존성을 스캔하여 새로 추가된 라이브러리와 그 라이브러리의 위험 가능성이 있는 동작을 식별하는 실험 기능입니다. Libbehave가 탐지한 각 기능에는 다음 중 하나의 "위험도" 점수가 부여됩니다:
Libbehave는 머지 리퀘스트 파이프라인에서 의존성을 스캔하여 새로 추가된 라이브러리와 그 라이브러리의 위험 가능성이 있는 동작을 식별하는 실험 기능입니다. 기존 의존성 스캐닝이 알려진 취약점을 찾는 반면, Libbehave는 의존성이 어떤 기능과 동작을 보이는지에 대한 인사이트를 제공합니다.
Libbehave가 탐지한 각 기능에는 다음 중 하나의 "위험도" 점수가 부여됩니다:
- 정보: 위험은 없지만 의존성의 기능을 정리하는 데 도움이 될 수 있습니다(예: JSON 사용).
- 낮음: 위험이 작으며, 의존성이 암호화 사용 같은 보안 민감 동작을 수행하고 있음을 드러낼 수 있습니다.
- 중간: 중간 수준의 위험으로, 민감한 데이터가 저장되거나 접근될 수 있는 파일 시스템과 상호 작용하거나 환경 변수를 읽는 데 사용될 수 있습니다.
- 높음: 가장 높은 수준의 위험으로, OS 명령을 실행하거나 코드를 동적으로 평가하는 등 보안 취약점에서 흔히 악용되는 동작입니다.
Libbehave가 탐지하는 기능은 다음과 같습니다:
- OS 명령 실행
- 동적 코드 실행(eval)
- 파일 읽기/쓰기
- 네트워크 소켓 열기
- 아카이브 읽기/확장(ZIP/tar/Gzip)
- HTTP 클라이언트, Redis, Elastic Cache, 관계형 데이터베이스 관리(RMDB) 서버, SSH, Git을 사용한 외부 서비스와의 상호 작용
- XML, YAML, MessagePack, Protocol Buffers, JSON 및 언어별 형식 등 다양한 형식의 데이터 직렬화
- 템플릿 처리
- 널리 쓰이는 프레임워크
- 파일 업로드/다운로드
지원되는 각 패키지 관리자 유형별 Libbehave 데모는 Libbehave 데모 프로젝트를 참고합니다.
지원되는 언어 및 패키지 관리자#
Libbehave는 다음 언어와 패키지 관리자를 지원합니다:
- C# (NuGet)
Directory.Build.props파일을 읽습니다(속성 값이 있으면 치환)*.deps.json파일을 읽습니다**/*.dll및**/*.exe파일을 읽습니다
- Go
go.mod파일을 읽습니다
- Java (Maven)
pom.xml파일을 읽습니다(속성 값이 있으면 치환)**/gradle.lockfile*파일을 읽습니다
- JavaScript/TypeScript (npmjs)
**/package-lock.json파일을 읽습니다**/yarn.lock파일을 읽습니다**/pnpm-lock.yaml파일을 읽습니다
- Python (pypi)
**/*requirements*.txt파일을 읽습니다**/poetry.lock파일을 읽습니다**/Pipfile.lock파일을 읽습니다**/setup.py파일을 읽습니다- egg 또는 wheel 설치 디렉터리의 패키지를 읽습니다:
**/*dist-info/METADATA,**/*egg-info/PKG-INFO,**/*DIST-INFO/METADATA,**/*EGG-INFO/PKG-INFO파일을 읽습니다
- PHP (Composer/Packagist)
**/installed.json파일을 읽습니다**/composer.lock파일을 읽습니다**/php/.registry/.channel.*/*.reg파일을 읽습니다
- Ruby (RubyGems)
**/Gemfile.lock파일을 읽습니다**/specifications/**/*.gemspec파일을 읽습니다**/*.gemspec파일을 읽습니다
위 파일들은 소스 브랜치에서 수정된 경우에만 새 의존성 분석 대상이 됩니다.
Libbehave 활성화#
사전 요구 사항:
- 프로젝트에 대한 Developer, Maintainer, Owner 권한.
- 파이프라인이 소스 및 대상 Git 브랜치가 정의된 활성 머지 리퀘스트 파이프라인의 일부여야 합니다.
- 프로젝트에 지원되는 언어 중 하나가 포함되어 있어야 합니다.
- 프로젝트가 소스 브랜치나 기능 브랜치에 새 의존성을 추가하고 있어야 합니다.
Libbehave를 활성화하려면:
-
상단 바에서 Search or go to를 선택하고 프로젝트를 찾습니다.
-
왼쪽 사이드바에서 Code > Repository를 선택합니다.
-
.gitlab-ci.yml파일을 선택합니다. -
Edit > Edit single file을 선택합니다.
-
Libbehave CI/CD 컴포넌트를 추가합니다:
include: - component: $CI_SERVER_FQDN/security-products/experiments/libbehave/libbehave@v0.1.0 inputs: stage: test -
Commit changes를 선택합니다.
이 구성은 test Stage에 libbehave-experiment라는 새 job을 생성합니다.
머지 리퀘스트 댓글 구성#
Libbehave의 머지 리퀘스트 댓글을 구성하려면 프로젝트 액세스 토큰을 구성합니다.
사전 요구 사항:
- 프로젝트에 대한 Maintainer 또는 Owner 권한.
- 프로젝트에 Libbehave가 활성화되어 있어야 합니다.
머지 리퀘스트 댓글을 구성하려면:
-
상단 바에서 Search or go to를 선택하고 프로젝트를 찾습니다.
-
왼쪽 사이드바에서 Settings > Access tokens를 선택합니다.
-
Add new token을 선택하고 다음 필드를 채웁니다:
- Token name: 이름을 입력합니다. 예를 들면
libbehave-bot입니다. - Role: Guest를 선택합니다.
- Select scopes: API 체크박스를 선택합니다.
- Token name: 이름을 입력합니다. 예를 들면
-
Create project access token을 선택합니다.
프로젝트 액세스 토큰을 클립보드에 복사합니다. 다음 단계에서 필요합니다.
-
Settings > CI/CD를 선택합니다.
-
Variables를 확장합니다.
-
Add variable을 선택하고 다음 필드를 채웁니다:
- Key:
BEHAVE_TOKEN을 입력합니다. - Value: 프로젝트 액세스 토큰을 붙여 넣습니다.
- Visibility: Masked를 선택합니다.
- Flags: Protect variable 체크박스를 선택 해제합니다.
- Key:
-
Add variable을 선택합니다.
CI/CD 컴포넌트가 BEHAVE_TOKEN을 자동으로 사용하므로 컴포넌트 입력에 따로 지정할 필요가
없습니다.
머지 리퀘스트 댓글은 소스 브랜치가 보호된 브랜치이거나 BEHAVE_TOKEN 변수의 Protect variable 옵션이 해제되어 있을 때만 표시됩니다.
사용 가능한 CI/CD 입력 및 변수#
CI/CD 변수로 Libbehave의 CI 컴포넌트를 커스터마이즈할 수 있습니다.
다음 변수는 Libbehave의 실행 방식을 구성합니다.
| CI/CD 변수 | CLI 인수 | 기본값 | 설명 |
|---|---|---|---|
CI_MERGE_REQUEST_SOURCE_BRANCH_NAME |
-source |
"" |
비교 대상 소스 브랜치(예: feature-branch) |
CI_MERGE_REQUEST_TARGET_BRANCH_NAME |
-target |
"" |
비교 대상 브랜치(예: main) |
BEHAVE_TIMEOUT |
-timeout |
"30m" |
패키지 분석 및 다운로드에 허용되는 최대 시간(예: 30m) |
BEHAVE_TOKEN |
-token |
"" |
선택 사항. 액세스 토큰(머지 리퀘스트 댓글 작성에 필요) |
CI_PROJECT_ID |
-project |
"" |
선택 사항. 결과를 머지 리퀘스트 노트로 작성할 프로젝트 ID |
CI_MERGE_REQUEST_IID |
-mrid |
"" |
선택 사항. 결과를 머지 리퀘스트 노트로 작성할 머지 리퀘스트 ID |
다음 플래그도 사용할 수 있지만, 검증되지 않았으므로 기본값을 유지하는 것이 좋습니다:
| CI/CD 변수 | CLI 인수 | 기본값 | 설명 |
|---|---|---|---|
BEHAVE_RULE_PATHS |
-rules |
"/dist" |
규칙 파일의 경로입니다. |
BEHAVE_TARGET_DIR |
-dir |
"" |
behave를 실행할 대상 디렉터리입니다. |
BEHAVE_NO_GIT_IGNORE |
-no-git-ignore |
true |
.gitignore의 파일을 스캔할지 여부입니다. 이 인수를 지정하면 스캔하지 않습니다. 기본적으로는 스캔합니다. |
BEHAVE_OUTPUT_PATH |
-output |
"behaveout" |
스캔 결과, 추출된 아티팩트, 보고서 결과를 저장할 경로입니다. |
BEHAVE_INCLUDE_LANG |
-include-lang |
"" |
포함할 언어로 csharp, go, java, js, php, python, ruby 중 하나를 ','로 구분해 지정하며, 지정하지 않은 나머지는 모두 제외합니다. |
BEHAVE_EXCLUDE_LANG |
-exclude-lang |
"" |
제외할 언어로 csharp, go, java, js, php, python, ruby 중 하나를 ','로 구분해 지정하며, 지정하지 않은 나머지는 모두 포함합니다. |
BEHAVE_EXCLUDE_FILES |
-exclude- |
"" |
정규 표현식으로 파일이나 경로를 제외하며, 각 정규 표현식은 ','로 구분합니다. |
모든 변수가 검증된 것은 아니므로 동작하는 변수와 그렇지 않은 변수가 있을 수 있습니다. 동작하지 않는 변수가 필요하다면 기능 요청을 제출하거나 사용할 수 있도록 코드에 기여합니다.
의존성 감지 및 분석#
Libbehave는 새로 추가된 의존성을 분석하고 발견 사항을 보고하며, 머지 리퀘스트 파이프라인에서 실행하도록 설계되었습니다. 따라서 머지 리퀘스트에 새 의존성이 없으면 Libbehave는 결과를 반환하지 않습니다.
감지 방식은 사용하는 언어와 패키지 관리자에 따라 다릅니다. 기본적으로 지원되는 패키지 관리자의 관련 파일을 파싱하여 어떤 의존성이 추가되고 있는지 식별합니다. 이렇게 수집한 정보로 각 패키지 관리자 API를 호출하여 식별된 패키지의 아티팩트를 다운로드합니다.
다운로드한 의존성은 추출된 뒤, 구성된 검사 집합과 함께 Semgrep 기반의 정적 분석 기법으로 분석됩니다.
Java와 C#의 경우 정적 분석을 실행하기 전에 바이너리 아티팩트를 디컴파일하는 단계가 추가로 수행됩니다.
알려진 문제#
각 언어에는 고유한 알려진 문제가 있습니다.
Gemfile.lock, requirements.txt 등 모든 패키지 파일은 명시적인 버전을 제공해야 합니다.
버전 범위는 지원되지 않습니다.
C##
.props또는.csproj파일의 속성·변수 치환은 중첩된 프로젝트 파일을 고려하지 않습니다. 추출된 전역 변수 집합과 그 값에 일치하는 변수를 모두 치환합니다.- 다운로드한 의존성을 디컴파일하므로 소스와 줄 번호가 1:1로 대응하지 않을 수 있습니다.
- Libbehave는 NuGet 패키지에 존재하는 모든 .NET 버전을 디컴파일합니다. 이 부분은 향후 최적화될 수 있습니다.
- 예를 들어 일부 의존성은 서로 다른 프레임워크 버전을 대상으로 하는 여러 DLL을 하나의 아카이브에 담습니다(예: net20/Some.dll, net45/Some.dll).
Java#
pom.xml파일의 상속을 지원하지 않습니다.- Maven만 지원하며 사용자 지정 JFrog 등 다른 아티팩트 리포지터리는 지원하지 않습니다.
- 다운로드한 의존성을 디컴파일하므로 소스와 줄 번호가 1:1로 대응하지 않을 수 있습니다.
Python#
- 분석을 위해 PyPI에서 소스 패키지를 다운로드하려고 시도합니다. 소스 패키지가 없으면
Libbehave는 가장 먼저 사용할 수 있는
bdist_wheel패키지를 다운로드하며, 이는 대상 OS와 맞지 않을 수 있습니다.
출력#
Libbehave는 다음 출력을 생성합니다:
- Job 요약: 어떤 기능이 탐지된 의존성에 있는지 빠르게 확인할 수 있도록 발견 사항 요약이 CI/CD 출력 job 콘솔에 바로 출력됩니다.
- MR 댓글 요약: 검토를 쉽게 하도록 발견 사항 요약이 머지 리퀘스트 댓글 노트로 출력됩니다. 이를 위해서는 job이 MR 노트 영역에 쓸 수 있도록 액세스 토큰을 구성해야 합니다.
- HTML 아티팩트: 검색 가능한 라이브러리 목록과 식별된 기능, 그리고 해당 발견을 유발한 정확한 코드 줄이 담긴 HTML 아티팩트입니다.
Job 요약#
Job 요약은 추가 구성이 필요 없으며 분석이 성공하면 항상 표시됩니다.
Job 요약 출력의 예시는 다음과 같습니다:
# Job output #
[=== libbehave: New packages detected ===]
🔺 4 new packages have been detected in this MR.
[= java - open-vulnerability-clients 6.1.7 =]
The https://mvnrepository.com/artifact/io.github.jeremylong/open-vulnerability-clients package was found to exhibit the following behaviors:
- 🟧 GzipReadArchive (Risk: Medium)
-----------------
[= java - jdiagnostics 1.0.7 =]
The https://mvnrepository.com/artifact/org.anarres.jdiagnostics/jdiagnostics package was found to exhibit the following behaviors:
- 🟥 CryptoMD5 (Risk: High)
- 🟧 WriteFile (Risk: Medium)
- 🟧 ReadFile (Risk: Medium)
- 🟧 ReadEnvVars (Risk: Medium)
-----------------
[= java - commons-dbcp2 2.12.0 =]
The https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 package was found to exhibit the following behaviors:
- 🟥 JavaObjectSerialization (Risk: High)
- 🟧 Passwords (Risk: Medium)
-----------------
[= java - jmockit 1.49 =]
The https://mvnrepository.com/artifact/org.jmockit/jmockit package was found to exhibit the following behaviors:
- 🟥 JavaObjectSerialization (Risk: High)
- 🟧 WriteFile (Risk: Medium)
- 🟧 ReadFile (Risk: Medium)
- 🟨 CryptoRAND (Risk: Low)
-----------------
MR 댓글 요약#
MR 댓글 요약 출력에는 Libbehave 컴포넌트를 구성한 프로젝트에 Guest 수준 액세스 권한을 가진 액세스 토큰을 만들어야 합니다. 그런 다음 해당 액세스 토큰을 프로젝트에 구성합니다. 기능 브랜치는 기본적으로 보호되지 않으므로 Protect variable 설정을 해제합니다. 그러지 않으면 Libbehave job이 액세스 토큰 값을 읽을 수 없습니다.

HTML 아티팩트#
HTML 아티팩트는 job 아티팩트 출력(behaveout/gl-libbehave.html)에 나타나며
job 아티팩트 다운로드에서 접근할 수 있습니다.

오프라인 환경(지원되지 않음)#
Libbehave는 여러 패키지 관리자에서 의존성을 직접 내려받으므로 오프라인 환경에서는 동작하지 않습니다.
문제 해결#
Job이 실행되지 않음#
Libbehave job이 실행되지 않으면 프로젝트가 머지 리퀘스트 파이프라인을 실행하도록 구성되어 있는지 확인합니다.
머지 리퀘스트 댓글이 추가되지 않음#
대개 BEHAVE_TOKEN 이 설정되지 않아 발생합니다. 액세스 토큰에 Guest 수준 액세스 권한이 있는지,
그리고 Settings > CI/CD 변수 설정에서 Protect variable 옵션이 해제되어 있는지
확인합니다.
오류: {401 Permission Denied}#
대개 BEHAVE_TOKEN에 올바른 값이 들어 있지 않아 발생합니다. 액세스 토큰에 Guest 수준 액세스
권한이 있는지 확인합니다.