SBOM
SBOM 예시
SBOM을 가장 빨리 이해하는 방법은 직접 읽어 보는 것입니다. 같은 소규모 애플리케이션을 CycloneDX와 SPDX로 보여 드리고, 각 필드의 의미, 부실한 SBOM의 모습, 자사 SBOM을 점검하는 방법을 설명합니다.
업데이트
예시의 애플리케이션
두 파일 모두 example-api 2.4.0을 설명합니다. 직접 종속성 express 하나를 가진 설명용 Node.js
서비스입니다. Express는 다시 accepts에 의존하므로, 예시에는 전이적 종속성도 하나 나타납니다. 실제 Express
애플리케이션의 SBOM에는 훨씬 많은 구성 요소가 나열되지만 구조는 같습니다.
CycloneDX SBOM 예시
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
"version": 1,
"metadata": {
"timestamp": "2026-10-30T09:00:00Z",
"lifecycles": [{ "phase": "build" }],
"tools": {
"components": [
{ "type": "application", "name": "example-sbom-tool", "version": "1.0.0" }
]
},
"component": {
"type": "application",
"bom-ref": "example-api",
"name": "example-api",
"version": "2.4.0"
}
},
"components": [
{
"type": "library",
"bom-ref": "pkg:npm/[email protected]",
"name": "express",
"version": "4.21.2",
"purl": "pkg:npm/[email protected]",
"licenses": [{ "license": { "id": "MIT" } }]
},
{
"type": "library",
"bom-ref": "pkg:npm/[email protected]",
"name": "accepts",
"version": "1.3.8",
"purl": "pkg:npm/[email protected]",
"licenses": [{ "license": { "id": "MIT" } }]
}
],
"dependencies": [
{ "ref": "example-api", "dependsOn": ["pkg:npm/[email protected]"] },
{ "ref": "pkg:npm/[email protected]", "dependsOn": ["pkg:npm/[email protected]"] }
]
}
| 필드 | 알려 주는 내용 |
|---|---|
specVersion |
파일이 사용하는 형식 버전으로, 도구가 파일을 구문 분석할 수 있게 합니다. |
serialNumber, version |
어떤 SBOM인지, 그리고 그 SBOM의 몇 번째 개정판인지. |
metadata.lifecycles |
SBOM이 만들어진 시점. 여기서는 빌드 중입니다. |
metadata.tools |
SBOM을 생성한 도구. 두 도구가 같은 커밋을 서로 다르게 보고할 수 있습니다. |
metadata.component |
SBOM이 설명하는 제품. |
purl |
패키지 URL. 도구가 구성 요소를 보안 권고와 매칭할 수 있게 하는 식별자입니다. |
licenses |
구성 요소의 선언된 라이선스. |
dependencies |
무엇이 무엇을 가져오는지. 이 필드 덕분에 accepts가 전이적 종속성으로 드러납니다. |
SPDX SBOM 예시
{
"spdxVersion": "SPDX-2.3",
"dataLicense": "CC0-1.0",
"SPDXID": "SPDXRef-DOCUMENT",
"name": "example-api-2.4.0",
"documentNamespace": "https://example.com/spdx/example-api-2.4.0",
"creationInfo": {
"created": "2026-10-30T09:00:00Z",
"creators": ["Tool: example-sbom-tool-1.0.0"]
},
"packages": [
{
"name": "example-api",
"SPDXID": "SPDXRef-Package-example-api",
"versionInfo": "2.4.0",
"downloadLocation": "NOASSERTION"
},
{
"name": "express",
"SPDXID": "SPDXRef-Package-express",
"versionInfo": "4.21.2",
"downloadLocation": "NOASSERTION",
"licenseDeclared": "MIT",
"externalRefs": [
{
"referenceCategory": "PACKAGE-MANAGER",
"referenceType": "purl",
"referenceLocator": "pkg:npm/[email protected]"
}
]
},
{
"name": "accepts",
"SPDXID": "SPDXRef-Package-accepts",
"versionInfo": "1.3.8",
"downloadLocation": "NOASSERTION",
"licenseDeclared": "MIT",
"externalRefs": [
{
"referenceCategory": "PACKAGE-MANAGER",
"referenceType": "purl",
"referenceLocator": "pkg:npm/[email protected]"
}
]
}
],
"relationships": [
{
"spdxElementId": "SPDXRef-DOCUMENT",
"relationshipType": "DESCRIBES",
"relatedSpdxElement": "SPDXRef-Package-example-api"
},
{
"spdxElementId": "SPDXRef-Package-example-api",
"relationshipType": "DEPENDS_ON",
"relatedSpdxElement": "SPDXRef-Package-express"
},
{
"spdxElementId": "SPDXRef-Package-express",
"relationshipType": "DEPENDS_ON",
"relatedSpdxElement": "SPDXRef-Package-accepts"
}
]
}
정보는 같고 배치만 다릅니다. SPDX는 packages 목록을 두고, 항목 간의 모든 연결을 relationships에
명시합니다. licenseDeclared는 패키지가 스스로에 대해 밝힌 내용이며, 도구가 알지 못하면
downloadLocation은 NOASSERTION일 수 있습니다. 배치 이외에 두 형식이 어떻게 다른지는
CycloneDX vs SPDX를 참조하세요.
부실한 SBOM의 모습
파일이 유효하더라도 거의 쓸모없을 수 있습니다. 다음을 확인하세요.
- 종속성 관계 없음. 평면 목록은 패키지가 있다는 사실만 알려 줄 뿐 무엇이 그 패키지를 가져왔는지는 알려 주지 않습니다. 전이적 종속성을 수정하려면 바로 이 정보가 필요합니다.
- 패키지 URL 없음. purl 같은 식별자가 없으면 구성 요소를 보안 권고와 매칭할 때 이름으로 추측할 수밖에 없습니다.
-
라이선스 누락. 많은 필드가
NOASSERTION으로 남아 있다면 SBOM이 라이선스 관련 질문에 답할 수 없다는 뜻입니다. - 의심스러울 만큼 적은 구성 요소. 대규모 애플리케이션에 구성 요소가 몇 개뿐이라면 대개 직접 종속성만, 또는 잠금 파일 하나에 선언된 것만 담겼다는 뜻입니다.
- 시점이나 방법에 대한 정보 없음. 도구와 생성 맥락이 없으면 SBOM이 어디까지 신뢰할 만하게 다루는지 알 수 없습니다.
- 공백에 대한 침묵. 좋은 SBOM은 보지 못한 것을 밝힙니다. 대부분의 파일은 그냥 끝나 버리고, 읽는 사람은 완전하다고 가정합니다.
자사 SBOM을 점검하는 방법
- 형식을 검증합니다. 해당 형식과 버전의 스키마 검증기로 검사하세요. 파일을 구문 분석하지 못하는 도구는 그 파일을 사용할 수 없습니다.
- 필드를 확인합니다. 2026 Minimum Elements 또는 고객이 요청한 목록과 비교하세요.
- 알고 있는 것을 검색합니다. 전이적 종속성 하나, 베이스 이미지의 패키지 하나, 빌드 도구 하나를 골라 어떤 것이 나타나는지 확인하세요.
- 두 출처를 비교합니다. 다른 방법으로 두 번째 SBOM을 생성해 차이를 살펴보세요. 한 파일에만 있는 구성 요소 하나하나가 다른 파일에 대한 질문이 됩니다.
NTIA, CISA, BSI 필드 목록에 대응시킨 모든 검사 항목은 SBOM 품질 체크리스트를 참조하세요.
CRACI의 빌드 시점 SBOM
CRACI도 같은 형식으로 내보냅니다. 다른 점은 내용이 어디서 오는가입니다. CRACI는 각 GitHub Actions 작업이 가져온 것을 기록하므로, SBOM의 모든 구성 요소는 실제로 빌드에 들어온 것이며, CI 캐시에서 복원된 패키지는 그렇게 표시됩니다. 워크플로가 실행한 GitHub Actions도 사용된 커밋에 고정된 구성 요소로 나타납니다. 각 작업의 SBOM에는 완전성 상태도 함께 담기므로, 공백을 직접 찾아야 하는 대신 명시적으로 알 수 있습니다. 빌드 시점 SBOM 생성 또는 SBOM 도구 비교를 참조하세요.
SBOM 예시: 자주 묻는 질문
SBOM은 어떻게 생겼습니까?
대개 JSON 파일이며, 때로는 XML입니다. 도구와 타임스탬프 같은 SBOM 자체에 대한 데이터로 시작하고, 이어서 각 구성 요소를 이름, 버전, 식별자, 라이선스와 함께 나열하며, 마지막으로 구성 요소들이 서로 어떻게 의존하는지 설명합니다.
SBOM은 JSON 파일입니까?
대개 그렇습니다. JSON은 CycloneDX와 SPDX 모두에서 가장 널리 쓰이는 인코딩이기 때문입니다. 두 형식 모두 다른 인코딩도 있으며, SPDX에는 태그-값 텍스트 형식도 있습니다.
SBOM의 purl이란 무엇입니까?
purl, 즉 패키지 URL은 pkg:npm/[email protected]와 같은 패키지의 표준 식별자입니다. 생태계, 패키지, 버전을 하나의 문자열로 나타내므로, 도구가 구성 요소를 취약점 데이터와 안정적으로 매칭할 수 있습니다.
SBOM에는 구성 요소가 몇 개 있어야 합니까?
정해진 개수는 없지만, 대개 직접 종속성보다 훨씬 많은 전이적 종속성이 포함되어야 합니다. 대규모 애플리케이션인데 구성 요소가 매우 적다면, 대개 도구가 일부만 보았다는 뜻입니다.
오픈 소스 프로젝트의 SBOM을 볼 수 있습니까?
경우에 따라 가능합니다. 일부 프로젝트는 릴리스와 함께 SBOM을 게시하며, GitHub는 리포지토리의 종속성 그래프에서 SBOM을 내보낼 수 있습니다. 이렇게 내보낸 SBOM은 특정 빌드가 사용한 것이 아니라 리포지토리가 선언한 내용을 반영합니다.
지금 쓰는 SBOM을 기록된 SBOM과 비교해 보세요
GitHub Actions 워크플로 하나를 CRACI에서 실행하고, 현재 SBOM에 나열되지 않은 구성 요소를 확인해 보세요.
데모 예약