SBOM
SBOM-voorbeelden
De snelste manier om een SBOM te begrijpen, is er een te lezen. Hier ziet u dezelfde kleine applicatie in CycloneDX en in SPDX, met wat elk veld betekent, hoe een zwakke SBOM eruitziet en hoe u uw eigen SBOM controleert.
Bijgewerkt op
De applicatie in deze voorbeelden
Beide bestanden beschrijven example-api 2.4.0, een illustratieve Node.js-service met één directe
afhankelijkheid, express. Express is op zijn beurt afhankelijk van accepts, dus de voorbeelden
tonen ook één transitieve afhankelijkheid. Een echte SBOM van een Express-applicatie vermeldt veel meer componenten,
maar de structuur is hetzelfde.
Voorbeeld van een 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]"] }
]
}
| Veld | Wat het u vertelt |
|---|---|
specVersion |
Welke versie van het formaat het bestand gebruikt, zodat tools het kunnen parsen. |
serialNumber, version |
Welke SBOM dit is, en welke revisie ervan. |
metadata.lifecycles |
Wanneer de SBOM is gemaakt. Hier: tijdens de build. |
metadata.tools |
Welke tool hem heeft geproduceerd. Twee tools kunnen dezelfde commit verschillend rapporteren. |
metadata.component |
Het product dat de SBOM beschrijft. |
purl |
De package URL, de identificator waarmee een tool het component aan advisories kan koppelen. |
licenses |
De gedeclareerde licentie van het component. |
dependencies |
Wie wie binnenhaalt. Hierdoor is accepts zichtbaar als transitieve afhankelijkheid. |
Voorbeeld van een 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"
}
]
}
De informatie is hetzelfde, maar anders ingedeeld. SPDX houdt een packages-lijst bij en vermeldt elke
koppeling tussen items in relationships. licenseDeclared is wat het pakket over zichzelf zegt,
en downloadLocation mag NOASSERTION zijn als de tool het niet weet. Zie CycloneDX vs SPDX
voor de verschillen tussen de twee formaten die verder gaan dan de opmaak.
Hoe een zwakke SBOM eruitziet
Een bestand kan geldig zijn en toch vrijwel nutteloos. Let hierop:
- Geen afhankelijkheidsrelaties. Een platte lijst vertelt u dat een pakket aanwezig is, niet wat het heeft binnengehaald, en dat is precies wat u nodig hebt om een transitieve afhankelijkheid op te lossen.
- Geen package URLs. Zonder identificator zoals een purl valt het koppelen van een component aan advisories terug op gissen op basis van namen.
-
Ontbrekende licenties. Veel velden die op
NOASSERTIONstaan, betekenen dat de SBOM licentievragen niet kan beantwoorden. - Verdacht weinig componenten. Een handvol componenten voor een grote applicatie betekent meestal alleen directe afhankelijkheden, of alleen wat één lockfile declareerde.
- Niets over wanneer of hoe. Zonder tool en generatiecontext kunt u niet beoordelen waarvoor u op de SBOM kunt vertrouwen.
- Zwijgen over hiaten. Een goede SBOM zegt wat hij niet kon zien. De meeste bestanden houden gewoon op, en een lezer gaat ervan uit dat ze volledig zijn.
Hoe controleert u uw eigen SBOM?
- Valideer het formaat. Haal het bestand door een schemavalidator voor het formaat en de versie, want een tool die het bestand niet kan parsen, kan het ook niet gebruiken.
- Controleer de velden. Vergelijk het met de 2026 Minimum Elements of de lijst waar uw klant om heeft gevraagd.
- Zoek naar iets wat u kent. Kies een transitieve afhankelijkheid, een pakket uit uw base image en een buildtool, en kijk welke daarvan voorkomen.
- Vergelijk twee bronnen. Genereer een tweede SBOM met een andere methode en bekijk het verschil. Elk extra component in het ene bestand is een vraag over het andere.
Een build-time SBOM van CRACI
CRACI exporteert dezelfde formaten. Het verschil zit in de herkomst van de inhoud: CRACI legt vast wat elke GitHub Actions-job heeft opgehaald, dus elk component in de SBOM is daadwerkelijk in de build binnengehaald, en pakketten die uit CI-caches zijn teruggezet, worden als zodanig gemarkeerd. GitHub Actions die de workflow heeft uitgevoerd, verschijnen ook als componenten, vastgepind op de gebruikte commit. De SBOM van elke job heeft bovendien een volledigheidsstatus, zodat de hiaten worden benoemd in plaats van dat u ze zelf moet vinden. Zie build-time SBOM-generatie, of hoe SBOM-tools zich tot elkaar verhouden.
SBOM-voorbeelden: veelgestelde vragen
Hoe ziet een SBOM eruit?
Meestal is het een JSON-bestand, soms XML. Het begint met gegevens over de SBOM zelf, zoals de tool en het tijdstempel, vermeldt daarna elk component met naam, versie, identificator en licentie, en beschrijft ten slotte hoe de componenten van elkaar afhangen.
Is een SBOM een JSON-bestand?
Meestal wel, omdat JSON de meest gebruikte codering van zowel CycloneDX als SPDX is. Beide formaten kennen ook andere coderingen, en SPDX heeft daarnaast een tag-value-tekstvorm.
Wat is een purl in een SBOM?
Een purl, of package URL, is een standaardidentificator voor een pakket, zoals pkg:npm/[email protected]. Hij noemt het ecosysteem, het pakket en de versie in één string, waardoor tools het component betrouwbaar aan kwetsbaarheidsgegevens kunnen koppelen.
Hoeveel componenten moet een SBOM hebben?
Er is geen juist aantal, maar transitieve afhankelijkheden horen erin te staan, en die zijn meestal veel talrijker dan de directe. Heel weinig componenten voor een grote applicatie betekent meestal dat de tool er maar een deel van heeft gezien.
Kunt u een SBOM van een open-sourceproject bekijken?
Soms. Sommige projecten publiceren SBOM's bij hun releases, en GitHub kan er een exporteren uit de dependency graph van een repository. Die export weerspiegelt wat de repository declareert, niet wat een specifieke build heeft gebruikt.
Vergelijk uw SBOM met een vastgelegde
Laat één GitHub Actions-workflow op CRACI draaien en zie welke componenten uw huidige SBOM niet vermeldt.
Demo boeken