SBOM 101
Lock file không phải SBOM: Những gì developer cần biết về software supply chain

TL;DR
- SBOM (Software Bill of Materials): Danh sách đầy đủ mọi component trong software, bao gồm transitive dependencies, licenses, suppliers, và security metadata
- Khác biệt quan trọng: package.json/requirements.txt chỉ là "công thức nấu ăn", SBOM là "nhãn dinh dưỡng" với đầy đủ nguồn gốc từng nguyên liệu
- Tại sao quan trọng: Log4j (CVE-2021-44228) cho thấy không ai biết chính xác mình có dùng vulnerable component hay không
- Bắt đầu ngay: Syft + Grype là combo miễn phí để generate và scan SBOM
Bạn có thể trả lời câu hỏi này trong 30 giây không?
Giả sử ngay lúc này, một CVE critical được công bố. Sếp hỏi: "Mình có đang dùng library X không?"
Bạn trả lời được không? Trong bao lâu?
Nếu câu trả lời là "để em check" và sau đó là hàng giờ grep qua repositories, thì bạn không đơn độc. Đó chính xác là những gì xảy ra với hầu hết các công ty khi Log4Shell (CVE-2021-44228) được công bố vào tháng 12/2021.
Tôi viết bài này để chia sẻ về SBOM - thứ mà tôi ước mình biết sớm hơn. Nó không phải silver bullet, nhưng nó giải quyết được vấn đề "mình đang chạy cái gì trong production" một cách có hệ thống.
SBOM là gì?
Software Bill of Materials (SBOM) là một danh sách chính thức, có cấu trúc, liệt kê tất cả các components tạo nên một phần mềm.
Nghe giống package.json hay requirements.txt? Không hẳn. Hãy nghĩ về sự khác biệt giữa công thức nấu ăn và nhãn dinh dưỡng:
- Công thức (package.json): "Cần express version 4.18.2" - đủ để npm install chạy được
- Nhãn dinh dưỡng (SBOM): Liệt kê tất cả 62 packages mà express depend vào, ai maintain chúng, license gì, có vulnerability nào không

Theo chuẩn NTIA/CISA, một SBOM tối thiểu cần 7 thông tin:
| # | Thành phần | Ví dụ |
|---|---|---|
| 1 | Supplier Name | "Lodash Maintainers" |
| 2 | Component Name | "lodash" |
| 3 | Version | "4.17.21" |
| 4 | Unique Identifiers | "pkg:npm/[email protected]" |
| 5 | Dependency Relationships | "depended on by: express" |
| 6 | Author of SBOM | "Generated by Syft" |
| 7 | Timestamp | "2024-01-15T09:30:00Z" |
Ngoài ra còn có thể có: licenses, checksums, known vulnerabilities, và VEX (Vulnerability Exploitability eXchange).
Tại sao package-lock.json không đủ?
Đây là câu hỏi tôi hay gặp: "Tôi đã có lock file rồi, sao cần SBOM?"
Hãy thử một thí nghiệm. Tạo một project Node.js với đúng một dependency:
{
"dependencies": {
"express": "^4.18.2"
}
}
Chạy npm install, rồi đếm:
$ ls node_modules | wc -l
62
62 packages. Cho một dependency.
Package-lock.json có liệt kê tất cả 62 packages. Nhưng nó không cho bạn biết:
- Package nào có license GPL (có thể conflict với license của công ty)
- Package nào không được maintain từ 3 năm nay
- Package nào có known vulnerabilities
- Package nào đến từ maintainer đã bị compromise account
So sánh chi tiết:
| Khía cạnh | package.json / lock file | SBOM |
|---|---|---|
| Mục đích | Build instructions | Complete inventory |
| Transitive deps | Liệt kê nhưng không có metadata | Đầy đủ info cho từng package |
| Licenses | Không có | Có |
| Supplier info | Không có | Có |
| Vulnerability data | Không có | Có thể tích hợp VEX |
| Standard format | Riêng từng ecosystem | SPDX, CycloneDX - cross-platform |
Log4j - Bài học đắt giá

Tháng 12/2021, CVE-2021-44228 được công bố. CVSS 10.0 - điểm tối đa. Một lỗ hổng trong Log4j, thư viện logging phổ biến nhất của Java.
Vấn đề? Log4j không chỉ là thứ developer import trực tiếp. Nó nằm trong:
- Apache Struts, Solr, Druid
- Elasticsearch, Logstash
- Minecraft (Java Edition)
- VMware vCenter
- ... và hàng nghìn enterprise applications khác
Nhiều công ty mất hàng ngày, thậm chí hàng tuần, chỉ để trả lời câu hỏi: "Mình có dùng Log4j không?"
Họ grep qua từng repository, mở từng pom.xml, check từng Dockerfile. Và vẫn không chắc đã tìm hết, vì Log4j có thể là transitive dependency của transitive dependency.
Nếu có SBOM cho mọi artifact, câu trả lời chỉ cần:
cat sbom.json | jq '.components[] | select(.name | contains("log4j"))'
30 giây thay vì 3 ngày.
SPDX hay CycloneDX?
Hai format SBOM phổ biến nhất hiện nay:
| Feature | SPDX | CycloneDX |
|---|---|---|
| Tổ chức | Linux Foundation (2011) | OWASP (2017) |
| Focus chính | License compliance | Security |
| Formats | Tag-value, RDF, JSON, XML | JSON, XML |
| VEX support | Separate spec | Built-in từ 1.4 |
| Learning curve | Steep hơn | Dễ bắt đầu |
Recommendation của tôi: Bắt đầu với CycloneDX nếu security là priority. Nó đơn giản hơn và có VEX built-in. Hầu hết tools đều hỗ trợ convert giữa hai formats, nên không phải quyết định một lần cho mãi mãi.
Hands-on: Generate SBOM với Syft
Lý thuyết đủ rồi. Thực hành thôi.
Syft là tool tôi recommend để bắt đầu. Nó từ Anchore, miễn phí, và là engine đằng sau lệnh docker sbom.
Cài đặt
# macOS
brew install syft
# Linux
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
Sử dụng
# Scan container image
syft nginx:latest
# Scan directory
syft ./my-project/
# Output CycloneDX JSON
syft nginx:latest -o cyclonedx-json > sbom.json
# Output SPDX
syft nginx:latest -o spdx-json > sbom.spdx.json
Sample output
Một entry trong CycloneDX SBOM:
{
"bom-ref": "pkg:npm/[email protected]",
"type": "library",
"name": "lodash",
"version": "4.17.21",
"purl": "pkg:npm/[email protected]",
"licenses": [
{
"license": {
"id": "MIT"
}
}
]
}
Mỗi component có: tên, version, purl (package URL - định danh unique), license. Đủ để query, đủ để tự động hóa.
Scan vulnerabilities với Grype
Có SBOM rồi, giờ làm gì với nó?
Grype - cũng từ Anchore - scan SBOM để tìm vulnerabilities:
# Cài đặt
brew install grype
# Scan
grype sbom:sbom.json
Output:
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
log4j-core 2.14.1 2.17.1 java CVE-2021-44228 Critical
log4j-api 2.14.1 2.17.1 java CVE-2021-44228 Critical
spring-boot-starter-web 2.5.4 2.5.8 java CVE-2021-22060 Medium
Rõ ràng. Actionable. Không cần đoán.
Tích hợp vào CI/CD

Đừng chờ đến khi có CVE mới rồi mới scan. Tích hợp vào pipeline:
// Jenkinsfile
stage('Generate SBOM') {
steps {
sh 'syft ${IMAGE_NAME}:${BUILD_NUMBER} -o cyclonedx-json > sbom.json'
archiveArtifacts artifacts: 'sbom.json'
}
}
stage('Vulnerability Scan') {
steps {
sh 'grype sbom:sbom.json --fail-on high'
}
}
Từ đó, mỗi build đều có:
- SBOM được generate và lưu trữ
- Vulnerability scan tự động
- Build fail nếu có high/critical vulnerabilities
Khi có CVE mới, bạn chỉ cần query archive:
for sbom in /archive/sboms/*.json; do
jq -e '.components[] | select(.name == "vulnerable-lib")' "$sbom" && echo "FOUND: $sbom"
done
Những điều SBOM không giải quyết được
Tôi không muốn oversell. SBOM có limitations:
1. SBOM cho biết "có gì", không cho biết "có nguy hiểm không"
Grype có thể báo 47 vulnerabilities. Nhưng bao nhiêu trong số đó thực sự exploitable trong context của bạn? Đây là lúc VEX (Vulnerability Exploitability eXchange) trở nên quan trọng - nó cho phép annotate: "CVE này tồn tại nhưng không exploitable vì X, Y, Z."
2. Quality phụ thuộc vào tool và cách generate
Scan container image cho kết quả khác với scan source code. Có dependencies chỉ xuất hiện ở runtime. Cần generate SBOM ở nhiều stages: source, build, và runtime.
3. SBOM không thay thế security practices khác
Nó không ngăn được developer commit credentials vào code. Không ngăn được SQL injection. Không thay thế penetration testing. SBOM là một layer trong defense-in-depth, không phải toàn bộ strategy.
Regulatory landscape
SBOM đang trở thành requirement, không chỉ nice-to-have:
- U.S. Executive Order 14028 (2021): Yêu cầu SBOM cho software bán cho federal government
- EU Cyber Resilience Act (2024): Yêu cầu SBOM cho products với digital elements
- FDA (2023): Yêu cầu SBOM cho medical devices
Nếu bạn bán software cho government hoặc trong regulated industries, đây không còn là optional.
Key Takeaways
- SBOM ≠ Lock file: package-lock.json cho reproducible builds, SBOM cho complete visibility
- Transitive dependencies là blind spot lớn nhất: Bạn có thể có hàng chục vulnerable components mà không biết
- Start simple: Syft + Grype, miễn phí, 10 phút để có SBOM đầu tiên
- Automate early: Integrate vào CI/CD pipeline ngay từ đầu
- SBOM là điểm bắt đầu: Từ đây có thể mở rộng sang VEX và AIBOM
Bắt đầu ngay
# Cài đặt
brew install syft grype
# Generate SBOM
syft your-image:latest -o cyclonedx-json > sbom.json
# Scan vulnerabilities
grype sbom:sbom.json
# Done.
Lần tới khi có CVE mới, bạn sẽ là người trả lời trong 30 giây, không phải 3 ngày.
Sources: