Процессы разработки должны быть построены так, чтобы гарантировать предсказуемый уровень безопасности продукта на выходе. Именно с такой идеей мы приступали к модернизации наших внутренних процессов в «ЛАНИТ ― Би Пи Эм».
Мы провели исследование мировых практик обеспечения безопасности, которые часто объединяют терминами AppSec (application security) и DevSecOps (development, security, and operations). Для нас было важно, что безопасность требуется не только при написании серверного кода. Фронт, инфраструктура, процессы сборки и развертывания также могут быть уязвимы. Поэтому мы обращали внимания на все эти аспекты. В этой и последующих статьях речь пойдет о наиболее интересных наших находках.
Первый аспект ― проверка качества используемых зависимостей. Мы изучили популярные решения на рынке: Dependency-Track, Mend, Snyk, Black Duck, Sonatype Lifecycle, JFrog Xray. Каждый из этих инструментов предлагает набор функций для обнаружения уязвимостей, интеграцию с CI/CD, но большинство из них являются коммерческими. Мы выбрали Dependency-Track от OWASP. Это бесплатное open-source решение, которое покрывает все наши запросы.
Про него уже написано несколько статей, например, здесь. Поэтому мы попробуем подсветить самые интересные нюансы, обнаруженные нами в ходе внедрения.
Кратко про принцип работы
Не вдаваясь в технические детали, которые можно найти в официальной документации, общий принцип работы Dependency-Track выглядит следующим образом.
Сбор информации о зависимостях. Инструмент собирает данные обо всех используемых зависимостях проекта, включая frontend, backend и любые другие компоненты, где есть зависимости.
Централизованное хранение и визуализация. Собранные данные отправляются на централизованный сервер, где они визуализируются в удобном интерфейсе. Это позволяет команде получать наглядное представление о состоянии безопасности зависимостей, управлять рисками и принимать обоснованные решения по их обновлению или замене.
Сканирование по базе уязвимостей. После сбора информации Dependency-Track проверяет все обнаруженные зависимости по базе данных уязвимостей, чтобы выявить потенциальные угрозы. Инструмент анализирует соответствие зависимостей известным уязвимостям, их критичность и влияние на проект.
Подключение к backend
Мы начали с backend на java. Встраивание в проект происходит достаточно просто. Существует maven-плагин для сбора информации о зависимостях в формате CycloneDX с хорошей документацией.
Подключение backend
<build>
<plugins>
<plugin>
<groupId>org.cyclonedx</groupId>
<artifactId>cyclonedx-maven-plugin</artifactId>
<version>${cyclonedx-maven-plugin.version}</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>makeAggregateBom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
В результате его работы создаются файлы в специальном формате SBOM со списком всех используемых в проекте зависимостей.
Далее этот файл должен попасть на сервер Dependency-Track, который разворачивается независимо и содержит красивый UI для визуализации. С его развертыванием у нас тоже не возникло проблем.
Подключение к frontend
Для фронта также имеется готовый плагин. Сборка и публикация зависимостей осуществляется в две команды. Суперпросто.
sh 'npx @cyclonedx/cyclonedx-npm --output-file bom.json --spec-version 1.5'
dependencyTrackPublisher artifact: 'bom.json', autoCreateProjects: true, projectName: 'project-name', projectVersion: "1", synchronous: true
Подключение к конвейеру
Мы хотели, чтобы при каждой сборке проекта информация о зависимостях собиралась и публиковалась на сервер, поэтому встроили этот шаг в CI/CD c помощью Jenkins-плагина.
Плагин легко интегрируется с Dependency-Track и имеет несколько удобных функций.
Первая хорошая новость была в том, что плагин позволяет блокировать сборку в зависимости от результата анализа базы уязвимостей. Каждая наша команда может настроить порог, после которого сборка будет падать в соответствии с собственными политиками и желаемым уровнем безопасности.
Еще один приятный момент ― можно отслеживать динамику по проекту. Тимлиды довольны.
Подводные камни
При внедрении в реальные проекты мы столкнулись с рядом нюансов, которые могут повлиять на эффективность и удобство работы с инструментом.
Локальная сборка
Для многих разработчиков критически важно обнаруживать уязвимые зависимости на самом раннем этапе, еще при локальной сборке, а не на конвейере CI/CD. Однако встроенного механизма для этого в Dependency-Track не нашлось.
Варианты решения
Публикация локальной сборки на сервер и ручной анализ через UI. Можно загружать BOM (Bill of Materials) с локальной сборки в Dependency-Track и проверять уязвимости вручную через веб-интерфейс. Однако этот подход неудобен и трудоемок, особенно для частых проверок в процессе локальной разработки.
Использование Dependency-Check. Это отдельная библиотека от OWASP, которая может быть встроена в процесс сборки. Она способна блокировать сборку при обнаружении уязвимых зависимостей. Можно настроить ее выполнение через Maven-профили, чтобы проверка запускалась только при локальных прогонах, не затрагивая CI/CD. Dependency-Check использует ту же базу данных уязвимостей, что и Dependency-Track, что делает этот вариант подходящим для раннего обнаружения проблем.
Использование специального плагина Maven. Он отправляет собранные зависимости на сервер и ожидает результатов анализа. Этот вариант непрактичен, так как он либо перетирает данные основного проекта, либо требует создания отдельных проектов для пользователя, что крайне неудобно. Поддержки бранчей в рамках одного проекта пока не предусмотрено.
Мы решили пожертвовать возможностью локальной проверки зависимостей. Для нас главным было качество сборок на конвейере.
Доверие к базе уязвимостей
Основной источник информации об уязвимостях — база NVD (National Vulnerability Database), которая поддерживается Национальным институтом стандартов и технологий США (NIST). Использование этой базы данных, несмотря на ее авторитет и надежность, может нести определенные риски.
Что, если доступ к базе будет закрыт? Прерывание связи с NVD может повлиять на своевременность получения данных об уязвимостях.
Что, если достоверность базы будет скомпрометирована? Возможные ошибки или манипуляции с данными могут снизить доверие к системе безопасности.
Однако Dependency-Track обладает возможностями, которые помогают минимизировать эти риски.
Локальная реплика базы уязвимостей. Dependency-Track создает свою копию базы данных и синхронизирует ее по мере возможности, что позволяет работать автономно без постоянного подключения к NVD. Это критично для обеспечения устойчивости процесса даже при потере связи с внешним источником. Также инструмент позволяет использовать зеркала вместо оригинальной базы.
Управление списком уязвимостей через UI. Интерфейс Dependency-Track позволяет вручную управлять списками уязвимостей, корректировать их, добавлять или исключать элементы по своему усмотрению. Это дает команде возможность гибко реагировать на изменяющиеся условия и поддерживать актуальность данных.
Можно вручную расширять список уязвимых зависимостей. Либо воспользоваться готовым, составленным локальными компаниями. Например, есть база данных угроз ФСТЭК.
Мы решили протестировать вышеупомянутую базу для расширения списка уязвимостей в Dependency-Track и столкнулись с рядом сложностей. Ниже основные выводы, которые мы сделали.
Несовместимость форматов. База ФСТЭК не поддерживает формат CVE, поэтому данные нужно вручную преобразовывать перед интеграцией с Dependency-Track. Это требует значительных временных затрат и создает дополнительную сложность при обновлении данных.
Пересечения с CVE. Часто записи из базы ФСТЭК ссылаются на уже существующие CVE, но сами по себе не являются полноценными уязвимостями для кода проекта. Это делает их более полезными для выявления уязвимых приложений и систем на рабочих станциях, а не для непосредственного анализа зависимостей в процессе разработки.
При желании запись из ФСТЭК можно вручную добавить в Dependency-Track. Несмотря на неудобства, связанные с преобразованием формата, записи из ФСТЭК можно перенести на локальный сервер Dependency-Track. Это позволяет расширить базу уязвимостей проекта, учитывая специфические угрозы, которые не охватываются международными источниками.
Если очень хочется, можно даже автоматизировать этот процесс и наполнять базу данных напрямую, минуя UI.
Управление ложными срабатываниями
Dependency-Track не только позволяет добавлять новые уязвимости, но и предоставляет инструменты для управления ложными срабатываниями. Это особенно полезно при работе с большим объемом данных, когда некоторые уязвимости могут быть ошибочно помечены как критические.
Фильтрация и настройка исключений. С помощью интерфейса можно исключать ложные срабатывания, добавлять комментарии и обоснования, что позволяет держать список актуальных уязвимостей под контролем.
Приоритизация угроз. Система позволяет задавать приоритеты и настраивать уведомления для наиболее критичных уязвимостей, фокусируясь на тех, которые представляют наибольшую угрозу для проекта.
Разделение доступа по проектам
Еще один нюанс использования Dependency-Track ― возможность сокрытия результатов анализа проекта для других команд.
Для некоторых проектов крайне важно не распространять информацию об уязвимостях за пределы команды. Ранее в Dependency-Track не было возможность разделить доступ к результатам анализа. Однако в последних версиях такая возможность появилась в beta-режиме.
Также имеется интеграция с LDAP/AD, а значит, можно использовать имеющийся в организации подход к авторизации. Поддерживается SSO с помощью OpenID. Однако аутентификация происходит не без участия пользователя. Вместо логина и пароля нужно нажать кнопку OpenID.
Результаты пилотирования
Пилотное внедрение Dependency-Track показало, что использование уязвимых зависимостей — это распространенная проблема, с которой сталкиваются практически все проекты, особенно в условиях активного использования open-source библиотек. Без таких специализированных инструментов, как Dependency-Track, разработчики часто не осознают наличие этой проблемы, а уязвимости могут оставаться незамеченными на протяжении всего жизненного цикла продукта.
Интеграция Dependency-Track в процесс разработки прошла быстро и без особых трудностей. Инструмент легко встроился в существующие пайплайны и начал приносить результаты практически сразу после настройки. Команда получила своевременные уведомления о выявленных уязвимостях и устаревших версиях.
Помимо анализа уязвимостей, использование Dependency-Track дало дополнительное преимущество — возможность автоматического анализа лицензий, используемых библиотек и компонентов. Этот аспект также важен для наших проектов, так как позволяет следить за соответствием лицензий внутренним требованиям и снижать риски нарушения интеллектуальных прав.
Таким образом, внедрение Dependency-Track не только улучшило контроль безопасности зависимостей, но и позволило обеспечить всесторонний подход к управлению рисками, связанными с использованием стороннего кода и лицензий. Это абсолютный must have на каждом проекте, где вы задумываетесь о безопасности продукта.