SBOM 101

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

SBOM 101
Photo by Calum Lewis / Unsplash

SBOM 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 ănnhã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

Từ công thức đơn giản đến nhãn dinh dưỡng đầy đủ thông tin

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ó
Supplier info Không 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á

Security teams khắp nơi khi Log4Shell được công bố

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

SBOM trong CI/CD Pipeline: Code → Build → SBOM → Scan → Deploy

Đừ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ó:

  1. SBOM được generate và lưu trữ
  2. Vulnerability scan tự động
  3. 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

  1. SBOM ≠ Lock file: package-lock.json cho reproducible builds, SBOM cho complete visibility
  2. 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
  3. Start simple: Syft + Grype, miễn phí, 10 phút để có SBOM đầu tiên
  4. Automate early: Integrate vào CI/CD pipeline ngay từ đầu
  5. 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: