
Сведения о заимствованных компонентах. Экскурс по созданию ППК (SBOM) в контексте подготовки заявки на сертификацию по требованиям ФСТЭК России
Проблематика
Одной из ключевых задач при подготовке заявки является формирование корректного файла с перечнем программных компонентов (ППК), он же Software Bill of Materials (SBOM). При кажущейся простоте на поверку эта задача на самом деле довольно нетривиальна, так как требует строгого соблюдения требований и рекомендаций ФСТЭК России. В данной статье рассмотрены основные принципы создания валидных SBOM-файлов.
1. Что такое SBOM
SBOM (Software Bill of Materials) — в общем случае это перечень программных компонентов, из которых состоит описываемый им продукт. В мире существует множество форматов для описания ППК, наиболее распространённые из них: CycloneDX и SPDX.
В рамках подготовки заявки на сертификацию по требованиям ФСТЭК России может потребоваться сформировать два ППК:
- Перечень заимствованных программных компонентов с открытым исходным кодом — ППК, который инвентаризирует все заимствованные программные компоненты с открытым исходным, используемые в составе программного обеспечения. Этот перечень является обязательным для предоставления вместе с заявкой, даже если в составе продукта нет ни одного заимствованного программного компонента с открытым исходным кодом.
- Перечень образов контейнеров — ППК, который инвентаризирует все образы контейнеров и все программные компоненты, входящие в состав этих образов. Данный перечень является обязательным только, если программный продукт является программным обеспечением в контейнерном исполнении, т.е. содержит в поставке хотя бы один образ контейнера, подлежащего выполнению в среде контейнеризации.
2. Поля SBOM файла
ППК представляет собой JSON-файл, соответствующий требованиям формата CycloneDX 1.6 с некоторыми уточнениями, которые зависят от вида ППК.
Перечень заимствованных программных компонентов с открытым исходным кодом должен соответствовать следующим требованиям.
Таблица 1. Требования к полям корневого объекта перечня заимствованных программных компонентов с открытым исходным кодом в машиночитаемом формате
| Имя поля | Тип | Описание | Требования к наличию |
|---|---|---|---|
bomFormat | JSON строка | Спецификация формата документа. Должно содержать значение «CycloneDX». | Обязательно |
specVersion | JSON строка | Версия спецификации документа. Должно содержать значение «1.6». | Обязательно |
serialNumber | JSON строка | Уникальный серийный номер документа, сгенерированный Разработчиком в соответствии с RFC-4122. Например, «urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79». | Опционально |
version | Целое число | Версия документа. Первоначальное значение — 1. При модификациях должна увеличиваться на 1. | Обязательно |
metadata | JSON объект | Дополнительная информация о перечне и продукте. Требования к заполнению полей объекта описаны в таблице 2. | Обязательно |
components | Массив объектов JSON | Список заимствованных программных компонентов с открытым исходным кодом. Если в продукте используется несколько версий одного и того же компонента, то для каждой версии компонента должна быть отдельная запись. Не допускается объединять в одну запись компоненты, исходный текст которых хранится в нескольких различных репозиториях систем управления версиями. Требования к заполнению полей объектов описаны в таблице 5. | Обязательно при наличии в составе ПО заимствованных компонентов |
Таблица 2. Требования к полям объекта, описывающего дополнительную информацию о перечне и продукте
| Имя поля | Тип | Описание | Требования к наличию |
|---|---|---|---|
timestamp | JSON строка | Дата и время формирования перечня в формате ГОСТ Р 7.0.64-2018 (ИСО 8601:2004). Например, «2022-04-25T09:30:00». | Обязательно |
component | JSON объект | Информация о продукте. Требования к заполнению полей объекта описаны в таблице 3. | Обязательно |
Таблица 3. Требования к полям объекта, описывающего информацию о продукте
| Имя поля | Тип | Описание | Требования к наличию |
|---|---|---|---|
type | JSON строка | Описывает тип заимствованного компонента. Допускается использовать следующие значения: application, framework, library, container, platform, operating-system, device, device-driver, firmware, file, machine-learning-model, data, cryptographic-asset. Данное поле является обязательным для совместимости со спецификацией CycloneDX, выбор типа компонента осуществляется по усмотрению разработчика. | Обязательно |
name | JSON строка | Название продукта. | Обязательно |
version | JSON строка | Версия продукта. Длина строки не должна превышать 1024 символа. | Обязательно |
manufacturer | JSON объект | Информация об изготовителе продукта. Требования к заполнению полей объекта описаны в таблице 4. | Обязательно |
Таблица 4. Требования к полям объекта, описывающего информацию об изготовителе продукта
| Имя поля | Тип | Описание | Требования к наличию |
|---|---|---|---|
name | JSON строка | Название организации – изготовителя продукта. | Обязательно |
Таблица 5. Требования к полям объекта, описывающего заимствованный программный компонент с открытым исходным кодом
| Имя поля | Тип | Описание | Требования к наличию |
|---|---|---|---|
type | JSON строка | Описывает тип заимствованного компонента. Допускается использовать следующие значения: application, framework, library, container, platform, operating-system, device, device-driver, firmware, file, machine-learning-model, data, cryptographic-asset. Данное поле является обязательным для совместимости со спецификацией CycloneDX, выбор типа компонента осуществляется по усмотрению разработчика. | Обязательно |
name | JSON строка | Наименование компонента. | Обязательно |
version | JSON строка | Версия компонента. | Обязательно |
purl | JSON строка | Опциональный идентификатор компонента в формате Package URL. | Опционально |
externalReferences | Массив объектов JSON | Массив объектов, описывающих источник, из которого осуществляется загрузка компонентов, исходных кодов компонента в собственный репозиторий изготовителя, а также другие внешние по отношению к документу ресурсы: документация, сайты и т.п. Требования к заполнению полей объектов описаны в таблице 6. Среди элементов массива обязательно должен присутствовать хотя бы один объект с типом vcs или source-distribution. | Обязательно |
properties | Массив объектов JSON | Массив объектов, описывающих свойства компонента. Требования к заполнению полей объектов описаны в таблице 8. Среди элементов массива обязательно должны присутствовать объекты со свойствами GOST:attack_surface и GOST:security_function. | Обязательно |
components | Массив объектов JSON | Список подкомпонентов данного компонента. Допускается получение информации как в массиве components родительского компонента, так и в массиве components корневого объекта перечня. Требования к заполнению полей объектов описаны в таблице 5. | Опционально |
Таблица 6. Требования к полям объекта, описывающего источники получения и внешние ссылки заимствованного компонента с открытым исходным кодом
| Имя поля | Тип | Описание | Требования к наличию |
|---|---|---|---|
type | JSON строка | Описывает тип внешнего ресурса. | Обязательно |
url | JSON строка | Если поле type имеет значение vcs, то в поле url помещается унифицированный указатель ресурса (URL) для репозитория с исходными текстами компонента, из которого осуществлялось копирование исходных кодов (например выполнение команды git clone) в собственный репозиторий изготовителя.Если поле type имеет значение source-distribution, то в поле url помещается унифицированный указатель ресурса (URL) для архива с исходным кодом компонента, который был использован для копирования исходных кодов компонента в собственный репозиторий изготовителя. | Обязательно |
hashes | Массив объектов JSON | Содержит список хэш-архива с исходным кодом компонента, полученных при помощи различных алгоритмов. Требования к заполнению полей объекта описаны в таблице 7. Если поле type имеет значение source-distribution, то данное поле является обязательным и среди его элементов обязательно должен присутствовать объект с идентификатором алгоритма STREEBOG-256 или STREEBOG-512. | Опционально |
Таблица 7. Требования к полям объекта, описывающего источники получения и внешние ссылки заимствованного компонента с открытым исходным кодом
| Имя поля | Тип | Описание | Требования к наличию |
|---|---|---|---|
alg | JSON строка | Содержит идентификатор алгоритма, которым был вычислен хэш архива с исходным кодом компонента или другого ресурса. | Обязательно |
content | JSON строка | Содержит значение хэш-функции для архива с исходным кодом компонента. Если alg имеет значение STREEBOG-256 или STREEBOG-512, то поле content должно содержать хэш-сумму архива с исходным кодом компонента, посчитанный по алгоритму ГОСТ Р 34.11 – 2012, с длиной хэш-кода 256 и 512 бит соответственно. | Обязательно |
Таблица 8. Требования к полям объекта, описывающего источник информации об уязвимости
| Имя поля | Тип | Описание | Требования к наличию |
|---|---|---|---|
name | JSON строка | Название свойства компонента. | Обязательно |
value | JSON строка | Значение свойства компонента. Если поле name имеет значение GOST:attack_surface, то поле value должно содержать одно из трёх значений:yes — в случае, если подпрограммы (функции) компонента реализуют программный интерфейс, который непосредственно доступен потенциальному нарушителю или входные данные которого потенциальный нарушитель способен гарантированно сформировать определенным образом. indirect — в случае, если подпрограммы (функции) компонента реализуют программный интерфейс, на входные данные которого потенциальный нарушитель способен целенаправленно повлиять, но это влияние существенно ограничено теми или иными факторами. no — в противном случае. Если поле name имеет значение GOST:security_function, то поле value должно содержать одно из трёх значений:yes — если функции компонента непосредственно реализуют функции безопасности средства защиты информации (например, принимают решение по возможности доступа субъекта к объекту; принимают решение о принадлежности анализируемого объекта к классу (например, вредоносного ПО, вредоносного трафика); формируют и осуществляют запись сведений о событиях в журнале; управляют функциями безопасности ядра ОС и процессора, предоставляющим возможности виртуализации и т. п.). indirect — если функции компонента участвуют в реализации функций безопасности средства защиты информации, взаимодействуя с компонентами, реализующими функции безопасности средства защиты информации (например, осуществление различных вида обработок подготовки данных, выделение структур данных из массива байт, выполнение вычислений над значениями аргументов функций и т. п.), но при этом не принимают непосредственных решений о запуске, останове, изменении режимов и параметров работы компонентов, реализующих функции безопасности. no — если функции компонента не участвуют в реализации функций безопасности средства защиты информации. | Обязательно |
Перечень образов контейнеров должен соответствовать следующим требованиям.
Таблица 9. Требования к полям корневого объекта перечня образов контейнеров в машиночитаемом формате
| Имя поля | Тип | Описание | Требования к наличию |
|---|---|---|---|
bomFormat | JSON строка | Спецификация формата документа. Должно содержать значение «CycloneDX». | Обязательно |
specVersion | JSON строка | Версия спецификации документа. Должно содержать значение «1.6». | Обязательно |
serialNumber | JSON строка | Уникальный серийный номер документа, сгенерированный Разработчиком в соответствии с RFC-4122. Например, «urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79». | Опционально |
version | Целое число | Версия документа. Первоначальное значение — 1. При модификациях должна увеличиваться на 1. | Обязательно |
metadata | JSON объект | Дополнительная информация о перечне и продукте. Требования к заполнению полей объекта описаны в таблице 10. | Обязательно |
components | Массив объектов JSON | Список образов контейнеров, входящих в состав средства. Требования к заполнению полей объектов описаны в таблице 13. | Обязательно |
Таблица 10. Требования к полям объекта, описывающего дополнительную информацию о перечне и продукте
| Имя поля | Тип | Описание | Требования к наличию |
|---|---|---|---|
timestamp | JSON строка | Дата и время формирования перечня в формате ГОСТ Р 7.0.64-2018 (ИСО 8601:2004). Например, «2022-04-25T09:30:00». | Обязательно |
component | JSON объект | Информация о продукте. Требования к заполнению полей объекта описаны в таблице 11. | Обязательно |
Таблица 11. Требования к полям объекта, описывающего информацию о продукте
| Имя поля | Тип | Описание | Требования к наличию |
|---|---|---|---|
type | JSON строка | Описывает тип продукта. Допускается использовать следующие значения: application, framework, library, operating-system, device-driver, firmware. Данное поле является обязательным для совместимости со спецификацией CycloneDX, выбор типа компонента осуществляется по усмотрению разработчика. | Обязательно |
name | JSON строка | Название продукта. | Обязательно |
version | JSON строка | Версия продукта. Длина строки не должна превышать 1024 символа. | Обязательно |
manufacturer | JSON объект | Информация об изготовителе продукта. Требования к заполнению полей объекта описаны в таблице 12. | Обязательно |
Таблица 12. Требования к полям объекта, описывающего информацию об изготовителе продукта
| Имя поля | Тип | Описание | Требования к наличию |
|---|---|---|---|
name | JSON строка | Название организации – изготовителя продукта. | Обязательно |
Таблица 13. Требования к полям объекта, описывающего образ контейнера
| Имя поля | Тип | Описание | Требования к наличию |
|---|---|---|---|
type | JSON строка | Описывает тип компонента. Должно содержать значение "container". | Обязательно |
name | JSON строка | Наименование образа контейнера. | Обязательно |
version | JSON строка | Версия компонента. | Обязательно |
purl | JSON строка | Опциональный идентификатор компонента в формате Package URL. | Опционально |
properties | Массив объектов JSON | Массив объектов, описывающих свойства компонента. Требования к заполнению полей объектов описаны в таблице 14. Среди элементов массива обязательно должны присутствовать объекты со свойствами GOST:attack_surface и GOST:security_function. | Обязательно |
components | Массив объектов JSON | Список программного обеспечения, входящего в состав образа контейнера. Требования к заполнению полей объектов описаны в таблице 15. | Обязательно |
Таблица 14. Требования к полям объекта, описывающего свойства компонентов
| Имя поля | Тип | Описание | Требования к наличию |
|---|---|---|---|
name | JSON строка | Название свойства компонента. | Обязательно |
value | JSON строка | Значение свойства компонента. Если поле name имеет значение GOST:attack_surface, то поле value должно содержать одно из трёх значений:yes — в случае, если подпрограммы (функции) компонента реализуют программный интерфейс, который непосредственно доступен потенциальному нарушителю или входные данные которого потенциальный нарушитель способен гарантированно сформировать определенным образом. indirect — в случае, если подпрограммы (функции) компонента реализуют программный интерфейс, на входные данные которого потенциальный нарушитель способен целенаправленно повлиять, но это влияние существенно ограничено теми или иными факторами. no — в противном случае. Если поле name имеет значение GOST:security_function, то поле value должно содержать одно из трёх значений:yes — если функции компонента непосредственно реализуют функции безопасности средства защиты информации (например принимают решение по возможности доступа субъекта к объекту; принимают решение о принадлежности анализируемого объекта к классу (например вредоносного ПО, вредоносного трафика); формируют и осуществляют запись сведений о событиях в журнал; управляют функционалом безопасности ядра ОС и процессора, предоставляющим возможности виртуализации и т. п.). indirect — если функции компонента участвуют в реализации функций безопасности средства защиты информации, взаимодействуя с компонентами, реализующими функции безопасности средства защиты информации (например, осуществляя различные виды обработки/подготовки данных, выделение структур данных из массива байт, выполнение вычислений над значениями аргументов функции и т. п.), но при этом не принимают непосредственных решений о запуске, остановке, изменении режимов и параметров работы компонентов, реализующих функции безопасности. no — если функции компонента не участвуют в реализации функций безопасности средства защиты информации. Если поле name имеет значение GOST:provided_by, то поле value должно содержать название сертифицированного средства защиты информации, из состава которого заимствован данный компонент, при условии, что изготовитель указанного средства обеспечивает поддержку безопасности этого компонента. | Обязательно |
Таблица 15. Требования к полям объекта, описывающего программное обеспечение, входящее в состав образа контейнера
| Имя поля | Тип | Описание | Требования к наличию |
|---|---|---|---|
type | JSON строка | Описывает тип компонента. Допускается использовать следующие значения: application, framework, library, container, platform, operating-system, device, device-driver, firmware, file, machine-learning-model, data, cryptographic-asset. Данное поле является обязательным для совместимости со спецификацией CycloneDX, выбор типа компонента осуществляется по усмотрению разработчика. | Обязательно |
name | JSON строка | Наименование компонента. | Обязательно |
version | JSON строка | Версия компонента. | Обязательно |
purl | JSON строка | Опциональный идентификатор компонента в формате Package URL. | Опционально |
properties | Массив объектов JSON | Массив объектов, описывающих свойства компонента. Требования к заполнению полей объектов описаны в таблице 14. Среди элементов массива обязательно должны присутствовать объекты со свойствами GOST:attack_surface и GOST:security_function. | Обязательно |
components | Массив объектов JSON | Список подкомпонентов данного компонента. Допускается перечислять подкомпоненты как в массиве components родительского компонента, так и в массиве components корневого объекта перечня. Требования к заполнению полей объектов описаны в таблице 15. | Опционально |
3. Создание SBOM файла
Для автоматизации процесса рекомендуется использовать следующие инструменты:
Выбор данных инструментов обусловлен их способностью генерировать SBOM с оптимальной гранулярностью данных. В отличие от аналогов (например, утилиты Syft), которые зачастую включают в отчет избыточные артефакты. Это обеспечивает строгое соответствие принципу минимизации данных и упрощает прохождение процедуры проверки соответствия требованиям регулятора.
Важно отметить, что полнота и корректность выходного файла напрямую зависят от доступности и структурированности исходных данных для парсинга. Применение выбранных инструментов является достаточным при условии, что алгоритм имеет возможность полного извлечения информации, что достигается при соблюдении следующих условий:
- Наличие стандартных манифестов: Проект использует стандартные пакетные менеджеры (npm, maven, pip, go mod и др.) и файлы манифестов доступны для парсинга.
- Отсутствие сложной обфускации: Исходный код и бинарные файлы не подвергались глубокой модификации или упаковке.
- Использование штатных репозиториев: Зависимости загружаются из публичных или доверенных репозиториев, имеющих стандартную метаинформацию.
В случаях, когда используется динамическая подгрузка библиотек в рантайме, проприетарные бинарные форматы или самописные системы сборки без явного декларирования зависимостей, данные инструменты могут давать неполную картину.
Типовым сценарием, в котором данный стек инструментов решает задачу в полной мере, является CI/CD пайплайн микросервисной архитектуры.
Пример: Веб-сервис на базе Node.js, упакованный в Docker-образ на основе Alpine Linux.
- Утилита cdxgen на этапе сборки анализирует package.json и package-lock.json, формируя точный список прикладных библиотек.
- Утилита Trivy после сборки образа сканирует слои Alpine Linux, выявляя системные пакеты. Результатом является исчерпывающий SBOM-файл, содержащий только верифицируемые компоненты, готовый к импорту в системы управления уязвимостями (например, Dependency-Track) и соответствующий требованиям регулятора.
Пример SBOM-файла для контейнеров
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"version": 1,
"metadata": {
"timestamp": "2024-11-25T00:00:00Z",
"component": {
"type": "application",
"name": "Самый лучший межсетевой экран",
"version": "72.15",
"manufacturer": {
"name": "ООО Ромашка"
}
}
},
"components": [
{
"type": "container",
"name": "manager",
"version": "3.0.0",
"properties": [
{ "name": "GOST:attack_surface", "value": "no" },
{ "name": "GOST:security_function", "value": "yes" }
],
"components": [
{
"type": "library",
"name": "romashka_manager",
"version": "0.07",
"properties": [
{ "name": "GOST:attack_surface", "value": "no" },
{ "name": "GOST:security_function", "value": "yes" }
]
},
{
"type": "library",
"name": "postgres",
"version": "16.4",
"properties": [
{ "name": "GOST:attack_surface", "value": "no" },
{ "name": "GOST:security_function", "value": "no" }
]
}
]
},
{
"type": "container",
"name": "gateway",
"version": "2.31.0",
"properties": [
{ "name": "GOST:attack_surface", "value": "yes" },
{ "name": "GOST:security_function", "value": "yes" }
],
"components": [
{
"type": "application",
"name": "romashka_gateway",
"version": "0.07",
"properties": [
{ "name": "GOST:attack_surface", "value": "no" },
{ "name": "GOST:security_function", "value": "yes" }
]
},
{
"type": "application",
"name": "nginx",
"version": "1.24.4",
"properties": [
{ "name": "GOST:attack_surface", "value": "yes" },
{ "name": "GOST:security_function", "value": "no" },
{ "name": "GOST:provided_by", "value": "CertifiedDistribution" }
]
}
]
}
]
}
В SBOM-файле, созданном для инвентаризации образов контейнеров, поле externalReferences указывать не требуется. Данное поле используется исключительно в SBOM-файле, который описывает компоненты целевого программного обеспечения.
Пример SBOM-файла для ПО
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"version": 1,
"metadata": {
"timestamp": "2024-04-25T00:00:00",
"component": {
"type": "application",
"name": "Самый лучший межсетевой экран",
"version": "72.15",
"manufacturer": {
"name": "ООО Ромашка"
}
}
},
"components": [
{
"type": "library",
"name": "openssl",
"version": "3.0.0",
"externalReferences": [
{ "type": "vcs", "url": "https://github.com/openssl/openssl/commit/89cd17a" }
],
"properties": [
{ "name": "GOST:attack_surface", "value": "yes" },
{ "name": "GOST:security_function", "value": "yes" }
]
},
{
"type": "library",
"name": "requests",
"version": "2.31.0",
"externalReferences": [
{ "type": "vcs", "url": "https://github.com/psf/requests/v2.32.3" }
],
"properties": [
{ "name": "GOST:attack_surface", "value": "yes" },
{ "name": "GOST:security_function", "value": "indirect" }
]
}
]
}
Важно отметить, что при составлении SBOM для программного обеспечения, входящего в состав сертифицированной операционной системы, поле externalReferences заполнять не требуется. Для таких пакетов достаточно в разделе properties добавить информацию о базовой ОС, указав свойство: "name":"GOST:provided_by", "value": "OS_NAME".
В поле externalReferences обязательно должен присутствовать хотя бы один объект с типом vcs или source-distribution. При source-distribution ссылка в поле url должна вести непосредственно на архив с исходным кодом для скачивания.
Для приведения изначально сгенерированных SBOM-файлов в соответствие c требованиями ФСТЭК России рекомендуется использовать специализированные скрипты.
Для проверки полученного SBOM файла рекомендуется использовать скрипт sbom-checker.py с ключами: -e (максимальное число ошибок для вывода, по умолчанию – 10), --check-vcs (проверка url на git/svn/hg/fossil-репозиторий для типа vcs в поле externalReferences; требуется доступ к интернету и наличие пакетов git, subversion и mercurial), --check-source-distribution (проверка url типа source-distribution). Ошибки типа ERROR обязательны к исправлению. Большинство ошибок типа WARNING являются обязательными к исправлению, но при проверке ссылок могут быть ложные срабатывания.
Если контейнер не является средой функционирования, то SBOM необходимо составлять только для целевого программного обеспечения.
Заключение
Формирование корректного SBOM-файла в контексте требований ФСТЭК России требует комплексного подхода. Резюмируя изложенное, можно выделить следующие ключевые выводы успешной подготовки SBOM файлов:
- Выбор стандарта: Строгое соблюдение спецификации CycloneDX версии 1.6 является обязательным базовым условием (с единственным отклонением в части использования нестандартных идентификаторов алгоритмов вычисления хэш-сумм архива STREEBOG-256 или STREEBOG-512).
- Подход: Методика формирования SBOM должна адаптироваться под среду функционирования (разделение для контейнеров и целевого ПО) и тип операционной системы (учет пакетов из состава сертифицированных ОС).
- Использование инструментов trivy и cdxgen эффективно решает задачи инвентаризации в типовых проектах с явным декларированием зависимостей. Однако результаты требуют обязательной валидации и доработки (externalReferences с ссылками на исходный код и атрибуты отнесения к ПА и ФБ) для устранения избыточности и приведения формата в полное соответствие с регуляторными нормами.
Соблюдение данных рекомендаций позволяет минимизировать недочеты при снятии SBOM файлов, а также создать перечень компонентов для контроля уязвимостей в программном обеспечении.
Автор:
Алексей Галкин, руководитель направления статического анализа, РУНЦ "Безопасность" МГТУ им. Н.Э. Баумана.