Привет! Это Angara Security и наш эксперт отдела безопасной разработки Андрей Быстров. Совсем недавно состоялся релиз OSA Proxy, нового модуля продукта CodeScoring.OSA. В этой статье попробуем разобраться в задачах данного модуля и подходах к его использованию.

Начать стоит с основ: каким образом реализуется проверка программного обеспечения с открытым исходным кодом в инструментах композиционного анализа на этапе OSA? Для наглядности приведем простую схему. Она также будет полезна в дальнейшем для сравнения архитектурных подходов к задаче проверки Open Source зависимостей.

Разберемся, что к чему:

1. Цель — концепция Shift Left, максимальное смещение проверок безопасности в самое начало процесса разработки ПО. Уязвимость или ошибку дешевле исправить на этапе запроса Open Source библиотек разработчиком внутри тестового окружения, не доходя до этапа сборки проекта в системах CI/CD.

2. Реализация — ставим «наблюдателя» на этапе получения и хранения компонентов внутри организации. Самый частый пример — менеджеры репозиториев/зависимостей (Sonatype Nexus Repository \ JFrog Artifactory \ harbor для докер-образов), удобно храним все зависимости (внутренние и Open Source) в единой точке, кэшируем и обращаемся по мере необходимости. Наш «наблюдатель» (чаще всего плагин) ставится поверх менеджера репозиториев, перехватывает входящие запросы на скачивание, сверяет с политиками безопасности, при необходимости блокирует.

Описанный выше механизм успешно применяется в различных инструментах. Попробуем порассуждать о его недостатках:

– Зависимость от продукта. При выстроенном процессе проверки Open Source компонентов могут возникнуть трудности, например, при миграции на другой менеджер репозиториев. Возникает связь между менеджером и инструментом ИБ. Также нельзя забывать про вопрос обратной совместимости, так в марте 2025 года Nexus Repository в релизе 3.78.0 провел миграцию на архитектуру Spring Boot, данное изменение повлекло за собой невозможность работы с кастомными плагинами (можно ознакомиться с подробным описанием проблемы от создателя одного из подобных плагинов https://community.sonatype.com/t/custom-plugins-still-possible-starting-with-3-78/14589).
Подобные ситуации сказываются на выстроенных процессах работы с ПО в компании, увеличивая время и стоимость разработки.

 – Особенности процессов и пакетных менеджеров. Схема с плагином идеально работает в ситуациях, когда разработчик точно знает версию нужной ему библиотеки. Но на практике это не всегда так. Количество прямых зависимостей в проекте может доходить до сотни и более, а есть еще и транзитивные (здесь также стоит упомянуть про политики безопасности в организации, мало знать конкретную версию пакета, нужно также чтобы она была разрешена к использованию). По сути, формирование итогового списка всех необходимых пакетов и библиотек лежит на плечах пакетного менеджера, который создает для нас условный package-lock.json.

В чем же сложность? Например, пакетный менеджер обратился к доступным публичным версиям пакета. Предположим, что нам нужен компонент npm/node-releases. Пакетным менеджером найдена свежая версия  npm/node-releases@2.0.27. При попытке скачивания она блокируется плагином по одной из политик. При разборе блокировки приходим к выводу, что можем получить версию npm/node-releases@2.0.25, так как она соответствует настроенным политикам. В этом случае мы должны вернуться и четко задать версию 2.0.25 для успешной загрузки в конкретном проекте. Если масштабировать процесс на количество разработчиков и зависимостей в проекте, получаем большое количество часов на триаж и разбор. Таким образом, мы теряем драгоценное время.

А что делать и делать ли?

Отметим, что приведенные механизмы работы с OSA-плагинами и их недостатки актуальны не везде и не для всех. Но, если вы столкнулись с одной из проблем, описанных выше, то, возможно, вас заинтересует идея модуля OSA Proxy.

Обзор модуля

OSA Proxy предоставляет альтернативу подходу с использованием плагина OSA.

Модуль несет в себе две важные особенности, отличающие его от плагина:

1. Независимость. Модуль не привязан к конкретной версии или производителю. Непринципиально, что используется в вашей организации, Sonatype Nexus Repository, JFrog Artifactory, и.т.д.

2. Сканирование манифестов. Появляется возможность проверять не только конкретную версию, но и запрос на манифесты (здесь и далее подразумевается полный список доступных версий пакета/библиотеки).

Погрузимся чуть подробнее в каждую из особенностей:

Независимость. Можно условно разделить варианты установки на три схемы. Пройдёмся по каждой из них с указанием «плюсов» и возможных нюансов, которые стоит учитывать.

1 вариант. Установка OSA Proxy между публичными репозиториями (интернет) и нашим менеджером репозиториев.

Плюсы

Минусы/нюансы

Все, что попало в наше внутреннее хранилище, проверено на соответствие политикам.

Изменились политики, а это значит, что в локальном хранилище могут остаться пакеты, которые должны блокироваться, но без проведения дополнительной очистки могут быть получены разработчиком.

Разработчикам не нужно изменять настройки пакетных менеджеров/сборщиков CI/CD, подключение остается неизменным.

Невозможность передавать вердикт о блокировке конечному клиенту (разработчику или сборщику CI/CD), ответ будет возвращен от менеджера репозиториев (в общем случае — безликое 404).

2 вариант. Установка OSA Proxy между менеджером репозиториев и клиентом (пакетным менеджером, сборщиком или разработчиком).

Плюсы

Минусы/нюансы

Каждый запрашиваемый на загрузку компонент проверяется на соответствие актуальным политикам.

Так как валидация проходит после менеджера репозиториев, в его локальном кэше могут оставаться невостребованные пакеты, содержащие уязвимости.

Упрощается триаж сработок, появляется возможность передать кастомизированный ответ от прокси-сервиса, содержащий причины блокировки компонента.

Вероятно, потребуется вносить изменения в рабочие процессы, так как меняется эндпойнт для получения компонентов разработкой.

3 вариант. Установка модуля OSA proxy между клиентами и публичными репозиториями, без кэширования компонент на стороне менеджера репозиториев. Данная конфигурация подойдет для организаций, которые в процессе разработки не используют собственные локальные репозитории. При небольшом количестве обращений за пакетами в сеть такая ситуация вполне вероятна. В таком варианте проксирующий сервис позволит проводить проверки зависимостей «на лету», не нужно разворачивать менеджер репозиториев для подключения плагина.

Ввиду характерной разницы третьего варианта относительно первых двух, не будем выделять его плюсы и минусы. Такой подход подойдет не всем, но пропустить его нельзя из-за новизны.

Описанные выше варианты предоставляют ту самую независимость. Модулю непринципиально, с каким менеджером репозиториев идёт взаимодействие и как он настроен. Выбор происходит, исходя из потребностей и процессов вашей команды.

Поддержка сканирования манифестов. Углубимся во вторую особенность модуля. В процессе сборки проектов разработчик задействует пакетные менеджеры для получения необходимых ему зависимостей.

Возьмём для примера pip-пакеты. Основной проблематикой применения блокирующих политик OSA в таком случае станет невозможность заранее предугадать, какую версию из множества доступных запросит для установки пакетный менеджер. Процесс резолва «под капотом» выглядит так:

● Обращение к индексу /simple/<package-name-for-install>/. Ответом является HTML-список со ссылками на все файлы релизов с их атрибутами (data-requires-python, data-yanked и т.д.).

● Отбор кандидатов. Package Finder формирует список кандидатов версий и файл релиза (wheel, sdist и т.д.).

● Фильтрация и дальнейший выбор. Pip отбирает пакеты, исходя из совместимых версий с вашим окружением. При наличии множества кандидатов выберется наиболее совместимый (например, cp310-cp310-manylinux_x86_64 лучше, чем py3-none-any для CPython 3.10 на Linux). В целом можно ожидать поведения «предпочитать новейшее», но это не всегда так.

● При установке можно ограничивать выбор (ограничивать версии «>=2.0,<3.0», использовать флаги --no-binary, --prefer-binary, --index-url и т.д.). Также возможно использование локального кэша от прошлых установок.

Какое влияние накладывает на это наш процесс OSA? Происходит следующее: механизмы pip выбрали версию, но при попытке установки происходит блокировка, потому что не пройдена политика безопасности OSA. Как результат: сборка неуспешна.

Именно на этом этапе можно получить другое поведение, OSA proxy способен заранее отфильтровать манифесты зависимостей.

Пакетный менеджер не сможет запросить версию, не соответствующую настроенным политикам, — он просто о ней не узнает! Блокируемые версии уже отфильтрованы. Как итог: мы получим более предсказуемые результаты сборок, количество остановок CI/CD процессов уменьшится.

Покажем, как выглядит процесс сканирования манифестов на примере https://pypi.org/project/requests/. Данная библиотека имеет несколько десятков версий (каждую из которых получит в HTML-списке наш пакетный менеджер при попытке установки). Часть этих версий не пройдёт через настроенные нами политики безопасности. Посмотрим на отфильтрованный список, который прошёл через сканирование модуля OSA Proxy:

##Выполняем запрос на машине, с развёрнутым и настроенным модулем

user@testx:~ # curl http://localhost:8080/codescoring-pypi/simple/requests/

<!doctype html>

<html lang="en">

<head>

<meta name="pypi:repository-version" content="1.4">

<meta name="pypi:project-status" content="active">

<title>Links for requests</title>

</head>

<body>

<h1>Links for requests</h1><a href="../../packages/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl#sha256=27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c" data-requires-python=">=3.8" rel="internal">requests-2.32.4-py3-none-any.whl</a><a href="../../packages/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz#sha256=27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422" data-requires-python=">=3.8" rel="internal">requests-2.32.4.tar.gz</a><a href="../../packages/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl#sha256=2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6" data-requires-python=">=3.9" rel="internal">requests-2.32.5-py3-none-any.whl</a><a href="../../packages/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz#sha256=dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf" data-requires-python=">=3.9" rel="internal">requests-2.32.5.tar.gz</a><!--SERIAL 30758180-->

</body>

Получаем список только разрешённых версий, прошедших по настроенным политикам (можете попробовать выполнить аналогичный запрос на публичный индекс curl https://pypi.org/simple/requests/ и сравнить результат).

Такой же список получит и пакетный менеджер, выбор конечной версии для установки будет происходить из измененного списка версий. Пакетный менеджер не узнал про запрещаемые нашими политиками версии, а мы избежали блокировки на этапе сборки.

Из событий OSA Proxy можем просмотреть события блокировки. Покажем для одной из версий. На деле такая строка будет для каждой исключенной версии:

2025-09-28T15:49:43.849Z INFO 1 --- [or-http-epoll-2] r.c.proxy.webclient.CodeScoringService : Request PURL: pkg:pypi/requests@2.32.2, Received response: blockStatus=blocked_by_policies, url=http://codescoring.test/p/osa/p/C1ktAjJgLQ/

url в конце события позволит перейти на страницу решения и получить отчёт о блокировке, по каким условиям произошла сработка, какие уязвимости были обнаружены и т.д.

Итогом станет появление возможности использования блокирующих политик OSA в процессе сборки. Мы исключаем вероятность получения пакетным менеджером информации о существовании версии, которая будет заблокирована при попытке скачивания. Данный подход может значительно облегчить процесс работы с внешними зависимостями, ускорить время доставки кода и заинтересовать вас, читателей, в возможном тестировании данного модуля.

Коротко о поставке решения

Проксирующий сервис представляет собой докер-образ, передаваемый вместе с конфигурационными файлами.

Требования к машине для установки весьма скромны, сервис не потребляет большого количества ресурсов.

На данный момент решение поддерживает проверку следующих пакетных менеджеров:

● Maven (maven-metadata.xml — манифест с информацией о версиях; .jar, .war, .ear — файлы пакетов);

● NPM (JSON — манифест пакета (путь /{repository}/*); .tgz — архивы пакетов);

● PyPI (HTML страницы Simple API (путь /{repository}/simple/*); .zip, .tar, .tgz, .tar.gz, .tar.bz2, .egg, .whl — файлы пакетов);

● NuGet (index.json — сервисный индекс Registration index JSON; .nupkg — файлы пакетов).

Подведем итог

Проксирующий сервис позволяет реализовать новые подходы к OSA-анализу в организациях, гибкость размещения относительно менеджера репозиториев даёт возможность выстраивания процессов проверки без ущерба для уже существующих процессов разработки.

Возможность сканирования манифестов может позволить более широкое применение OSA-анализа в процессах сборки, оказывая меньшее влияние на скорость доставки относительно классической схемы с плагинами.

На данный момент поддерживается не такой широкий перечень пакетных менеджеров, что не позволит провести полноценную миграцию и отказаться от механизмов плагина вовсе, однако уже сейчас модуль может закрывать часть используемого стека технологий.

Если один из недостатков применения плагинов, описанный выше в статье, был для вас препятствием к реализации проверок OSA, возможно, вам стоит обратить внимание на новые возможности, предоставляемые данным модулем.

Всем безопасной разработки!

Комментарии (0)