open atlas
↑ К треку
Защитная безопасность BLUE · 04 · 02

SBOM и цепочка поставок

Выходит новый CVE в зависимости, и первый вопрос — «затронуты ли мы?». SBOM — поштучная опись всего, что вы поставляете в сборке, — позволяет ответить за минуты, а не за дни. Provenance и SLSA добавляют недостающую половину: доверие к этой описи.

BLUE Middle ◷ 15 min
Уровень
ОсновыJuniorMiddleSenior

Декабрь 2021-го, поздний вечер: выходит CVE на Log4j 2 — CVE-2021-44228, удалённое выполнение кода через одну подделанную строку лога, оценка 10.0. Все security-каналы взрываются. Технический директор задаёт единственный важный вопрос: затронуты ли мы? И в комнате повисает тишина. Никто не может ответить. Log4j нет в верхнем уровне ни package.json, ни pom.xml — это транзитивная зависимость на четыре слоя вглубь, которую притянул логирующий адаптер, понадобившийся фреймворку. Она может быть в трёх сервисах, а может в тридцати. Команды, ответившие за двадцать минут, имели Software Bill of Materials — запрашиваемый, попсборочный список каждого компонента, который они поставляли. Команды, ответившие за девять дней, руками грепали репозитории исходников. Тот же баг, тот же патч — разница была целиком в том, знали ли они, что у них запущено.

К концу этого урока ты будешь знать, что на самом деле содержит SBOM, почему на вопрос «затронуты ли мы?» нельзя ответить без неё и почему знать свои зависимости — лишь половина работы: вторая половина — доверять им.

Что такое SBOM на самом деле

Software Bill of Materials (опись состава ПО) — это формальная, машиночитаемая опись каждого компонента в программном продукте: прямых зависимостей, транзитивных зависимостей и часто OS-пакетов, запечённых в образ контейнера. Ментальная модель — это этикетка состава на продукте питания: не маркетинговый текст, а буквальный список того, что внутри, в формате, который машина может разобрать, а регулятор — проверить. На практике доминируют два стандарта: SPDX (стандарт ISO, ISO/IEC 5962) и CycloneDX (от OWASP, спроектированный с приоритетом безопасности). Оба выражают одни и те же ключевые факты — имя компонента, версию и уникальный идентификатор под названием purl (package URL, например pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1) — плюс криптографический хеш, чтобы можно было доказать, что артефакт не подменили.

Единственное свойство, ради которого SBOM стоит генерировать, — то, что она захватывает транзитивный граф, а не только верхний уровень. Когда ты делаешь npm install express, ты притягиваешь десятки пакетов, которые никогда не называл; дерево зависимостей реального приложения регулярно доходит до нескольких сотен или тысячи узлов. Уязвимости, которые бьют, почти всегда живут в этом погребённом большинстве — Log4j была на четыре уровня вглубь, — а это ровно там, где человек, читающий package.json, их не видит. SBOM сплющивает весь этот граф в список, который можно запросить: «встречается ли где-нибудь в этой сборке хоть одна версия log4j-core превращается из многодневных раскопок в однострочный запрос.

Неочевидное правило: SBOM генерируется на этапе сборки, для каждого артефакта, а не пишется руками. Список зависимостей, поддерживаемый вручную, устаревает в тот момент, когда кто-то поднимает версию в lock-файле, а устаревший — хуже, чем никакой, потому что он уверенно лжёт. SBOM — это выход сборки, привязанный к конкретному digest образа, поэтому он описывает ровно те байты, которые ты задеплоил, а не то, что обещает README.

Почему «затронуты ли мы?» — это весь смысл

SBOM не имеет ценности, лёжа в бакете. Её ценность реализуется, когда выходит новая уязвимость и ты подаёшь SBOM в сканер, который сопоставляет purl каждого компонента с CVE-фидом. Это разница между описью и обнаружением: опись говорит, что у тебя есть; скан говорит, что из этого теперь известно как опасное. Поскольку новые CVE публикуются каждый день против компонентов, которые ты заморозил месяцы назад, сопоставление должно быть непрерывным — уязвимость, которая была чистой на момент сборки, становится критической в день выхода своего CVE, а сохранённая SBOM — это то, что позволяет дотянуться назад и найти её, ничего не пересобирая и не перегрепывая.

Здесь же входит приоритизация, потому что реальный скан против дерева в тысячу узлов возвращает десятки попаданий, а пропатчить их все за неделю нельзя. CVSS — Common Vulnerability Scoring System — даёт каждому CVE базовый балл 0–10, вендоронезависимую серьёзность, сравнимую между командами. Но базовый балл намеренно худший-случай и без контекста: он предполагает, что уязвимый код достижим, а актив открыт. Зрелый ход — наложить средовые и временные метрики CVSS — действительно ли этот компонент на достижимом пути? обращён ли актив в интернет? существует ли эксплойт в дикой природе? — поверх базового балла. CVE с базовым 9.8 в dev-only сборочном инструменте, который ты никогда не поставляешь, — это меньший реальный риск, чем 7.5 в твоём обращённом в интернет сервисе аутентификации. SBOM говорит, где находится компонент, а это ровно тот контекст, что превращает сырой балл в реальный приоритет.

Почему это работает

Почему грепать репозитории «недостаточно хорошо» вместо генерации SBOM? Потому что исходник ≠ артефакт. Репозиторий показывает, что ты написал; SBOM показывает, что ты поставил. Транзитивная зависимость, разрешённая твоим lock-файлом, OS-пакет базового образа, вендоренный бинарник, версия, по-разному запиненная в CI и локально, — ничего из этого не видно из grep по дереву исходников, и всё это уезжает в контейнер. Команды Log4j, которые грепали, нашли свои прямые использования и упустили адаптер фреймворка, который притянул её транзитивно. SBOM генерируется из разрешённой сборки, поэтому видит байты, а не намерения.

Вторая половина: provenance и доверие

Знать, что ты поставляешь, — лишь половина проблемы цепочки поставок. Вторая половина — доверять, что компонент, который ты притянул, — это тот, который его автор действительно опубликовал, и этот вопрос стал острым после атак вроде SolarWinds (2020), где вредоносный код внедрили в сборочный конвейер, так что подписанный официальный артефакт сам оказался отравлен, и Codecov и захвата npm-пакета event-stream, где легитимный пакет перехватили и выкатили вредоносную версию. Во всех случаях имя зависимости и версия выглядели верно. SBOM сказала бы тебе, что ты запускаешь этот пакет; она не сказала бы, что пакет подменили выше по течению. Этот зазор закрывает provenance.

Provenance — это проверяемые, защищённые от подделки метаданные, отвечающие на вопрос откуда взялся этот артефакт, из какого коммита исходника, собран каким конвейером? — криптографически подписанные, чтобы их нельзя было подделать задним числом. SLSA (Supply-chain Levels for Software Artifacts, читается «сальса») — это фреймворк, который оценивает, насколько этому provenance можно доверять, по уровням: грубо, L1 означает, что provenance существует, L2 — что он подписан сборочным сервисом, а L3 — что сборка прошла в укреплённом, изолированном окружении, которое производитель не может подделать. Цель — комбинированная позиция: SBOM, чтобы знать свои компоненты, provenance, чтобы доверять их подлинности, и SLA на патчинг — вроде сроков, предписанных NIST SP 800-40, — чтобы заведомо плохой компонент чинился по часам, а не когда кто-нибудь заметит.

Выбери лучший вариант

Только что вышел критический CVE на удалённое выполнение кода в популярной логирующей библиотеке. Технический директор спрашивает: «Затронуты ли мы и где?» Какая способность реально отвечает на это за минуты?

Викторина

Почему SBOM нужно генерировать на сборке для каждого артефакта, а не поддерживать как написанный вручную документ?

Викторина

Атакующий компрометирует сборочный конвейер и поставляет отравленную версию официального, корректно названного пакета (в стиле SolarWinds). Какой контроль поймал бы это, а какой — нет?

Расставь шаги по порядку

Упорядочь рабочий процесс цепочки поставок от сборки до ответа на «затронуты ли мы?»:

  1. 1 Сборка разрешает все зависимости (прямые + транзитивные + базовый образ)
  2. 2 Сгенерировать SBOM на артефакт, привязанную к digest образа
  3. 3 Сохранить SBOM рядом с задеплоенным артефактом
  4. 4 Непрерывно сопоставлять каждый purl со свежими CVE-фидами
  5. 5 На новый CVE запросить SBOM и приоритизировать попадания по CVSS + достижимости
Вспомните перед уходом
  1. 01
    Что именно содержит SBOM и почему важно генерировать её на сборке для каждого артефакта?
  2. 02
    Знать свои зависимости — лишь половина проблемы цепочки поставок; в чём вторая половина и что её закрывает?
Итог

SBOM — это формальная, машиночитаемая опись каждого компонента, который ты поставляешь, — прямого, транзитивного и из базового образа, — выраженная в SPDX или CycloneDX с purl и хешем на компонент. Весь смысл её существования — вопрос, который навязывает свежий CVE: «затронуты ли мы и где?». Поскольку опасные компоненты почти всегда погребены глубоко в транзитивном графе (Log4j была на четыре уровня вглубь), чтение манифеста или grep по исходнику даёт уверенный-но-неверный ответ, тогда как SBOM со сборки, непрерывно сканируемая против CVE-фидов, отвечает на него за минуты — а дальше базовые баллы CVSS плюс контекст достижимости и открытости превращают десятки попаданий в реальный приоритет патчинга. Но опись — не доверие: атаки в стиле SolarWinds отравляют корректно названные официальные артефакты, что одна SBOM поймать не может, поэтому ты дополняешь её provenance и SLSA, чтобы доказать подлинность компонентов, и SLA на патчинг, чтобы чинить плохие по часам. Теперь, когда выходит критический CVE в зависимости, твой первый ход — не грепать, а запросить SBOM и спросить, какое из попаданий реально достижимо и открыто.

Практика

Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.

вспомнитьприменитьуглубить0 из 6 завершено
Связанные уроки

Что-то непонятно?

Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.

хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources2
expand
  1. 01
  2. 02

Trademarks belong to their respective owners. Editorial reference only.