Автор – Юрий Шабалин, ведущий архитектор Swordfish Security
Построение процесса безопасной разработки несколько лет назад чаще всего начинали с практики анализа кода. Это и неудивительно, она была одной из самых понятных и простых для внедрения и давала наилучший результат с точки зрения временных и ресурсных затрат, с одной стороны, и покрытия по уязвимостям - с другой. Нужно лишь “скормить” сканеру исходники и получить на выходе уязвимости, - что может быть проще.
Но с недавнего времени все большую популярность и востребованность получает практика анализа компонент с открытым исходным кодом, когда каждая включенная в продукт библиотека проходит проверку на безопасность и наличие в ней публично задекларированных уязвимостей и недекларированных возможностей.
Востребованность такого анализа не вызывает сомнений. Согласно статистике, использование библиотек с открытым исходном кодом в больших проектах может достигать более 30-40% от всего кода приложения, а в некоторых случаях и больше. Что и говорить, если за прошлый год появилось более 6 миллионов новый версий библиотек, а суммарное количество компонент, которые можно использовать, превысило отметку в 37 миллионов. При этом, количество загрузок различных библиотек составило более 2,2 триллионов за 2021 год.
Все эти миллиарды строчек кода пишут люди, которые могут допускать ошибки (не говоря уже о случаях, когда вредоносный функционал встраивается специально, что также нередко случается). В исследованиях отмечается, что более 29% процентов популярных библиотек содержит уязвимости. А количество атак через них увеличилось на 650% по сравнению с прошлым годом.
И действительно, за последнее время атаки на приложения через библиотеки с открытым исходным кодом стали намного популярнее, и некоторым уязвимостям даже стали давать имена. Вспомнить хотя бы нашумевшую недавно историю с Log4Shell, которая позволяла выполнить любой код на сервере удаленно! Если посмотреть на то, как ее пытались использовать, то цифры получаются очень интересными. Во-первых, для реализации этой уязвимости было написано более 60-ти готовых эксплойтов, и в отдельные промежутки времени можно было наблюдать до 100 попыток атак в минуту. Во-вторых, хакерские группировки суммарно провели более 1,5 миллиона атак, направленных на эту уязвимость, в течение четырех дней после публикации уязвимости.
Количество атак через Log4shell
И таких примеров - множество. Уязвимости в openSSL, используемом повсеместно, нередко ужасают общественность. До сих пор мы помним багу в библиотеке struts2, через которую произошел самый массовый слив данных компании Equifax и многое другое.
А сейчас мы наблюдаем новую тенденцию: в связи с событиями последних месяцев некоторые активисты начали выпускать новые версии библиотек с заложенным в них зловредным функционалом, нацеленным специально на Россию или Российские ip-адреса. У некоторых были лишь небольшие изменения, которые выводили в лог какое-то сообщение, но в некоторых случаях код либо полностью отключал необходимый функционал, либо старался вообще удалить весь код, до которого мог дотянуться.
Эти события поставили под удар ряд проектов, в которых используется ПО на базе Open Source. Несмотря на то, что в открытом доступе можно найти списки известных на данный момент библиотек с подобным функционалом, это мало помогает. Ведь просто имея на руках такой файлик и тысячи разрабатываемых сервисов, очень сложно понять и определить, где и какие версии библиотек используются. И вот тогда можно оценить преимущества грамотно выстроенного процесса безопасной разработки, и в частности, практики анализа компонент. Ниже мы рассмотрим несколько проектов внедрения такой практики, их результатах и оценим, насколько это помогает решать проблемы использования библиотек с открытым исходным кодом.
Для начала посмотрим, как был выстроен процесс анализа компонент с открытым исходным кодом для одной достаточно крупной финансовой организации. Скажем сразу, что у нее имеется очень грамотный и хорошо выстроенный процесс разработки, с единым конвеером CI/CD и общими сервисами разработки в рамках компании (единый репозиторий исходного кода, артифакторий для хранения библиотек с и т.д.).
В первую очередь, было решено начать с анализа артифактория, оценив, что именно в нем хранится с точки зрения внешних зависимостей. Пройдясь по всем имевшимся библиотекам и их версиям, специалисты немало удивились, обнаружив несколько десятков тысяч различных компонент для разных языков программирования с различных источников. При этом одна и та же библиотека могла быть представлена в огромном количестве различных версий. BouncyCastle для java, к примеру, была представлена практически всеми существующими на тот момент времени версиями (за исключением всего нескольких штук). Захотелось в какой-то момент их тоже скачать, чтобы была уже полная коллекция.
После того, как данные были получены и стал понятен масштаб проблем, метаданные хранящихся библиотек были отправлены в инструмент по анализу библиотек. На выходе был получен отчет, содержащий около 50 тысяч уязвимостей, 5% - критических (оценка по шкале критичности 9 и более из 10 возможных), 10% - высоко опасных (8-9 из 10). Их эксплуатация позволяла в некоторых случаях получить полный контроль над сервисом компании. Это был впечатляющий результат, хотя и ожидаемый, учитывая количество компонент в репозитории (условно, каждая библиотека содержала как минимум одну уязвимость).
Первым шагом стало удаление из внутреннего репозитория самых уязвимых библиотек и запрет на загрузку компонент, баги в которых имели критический уровень опасности. Но дальше встал вопрос, что делать со всем остальным, как понять, какой сервис какую библиотеку и какую версию использует.
Решение нашлось довольно быстро - была внедрена практика, при которой каждая команда в конвейере использует свой собственный репозиторий, в котором хранится актуальный список компонент, используемых ими в процессе разработки ПО. Планомерно мы распространили этот подход на все команды в конвейере и стали более чётко понимать, какие библиотеки каких версий в каких сервисах компании используются. Этот шаг позволил, во-первых, вычистить репозиторий от самых опасных вещей, во-вторых, помог немного наладить процесс разработки и дал первичное понимание, какие команды какие библиотеки используют и какие внутри них есть уязвимости. Был проведен более тщательный анализ этих репозиториев. Затем командам разработки была поставлена задача в кратчайшие сроки перейти на использование неуязвимых версий библиотек (пока что только для высокого и критического уровня).
После реализации первого шага удалось добиться снижения общего уровня уязвимостей на 25%, так как обновление до неуязвимых версий помимо критических уязвимостей устранило и ряд менее серьезных проблем. Простой шаг, который позволил значительно улучшить защищенность продуктов и поднял уровень понимания их использования в компании.
Далее, специалисты взялись за несколько направлений. Во-первых, продолжилась работа по «вычистке» библиотек из репозиториев, а те, что остались, были поставлены на периодический мониторинг. Ведь даже тот репозиторий, что еще вчера был безопасен, сегодня может иметь самый высокий уровень угрозы (как было с тем же Log4j).
Во-вторых, анализ итоговых артефактов (уже собранных) или работы с исходным кодом (построение актуального файла с используемыми версиями библиотек при помощи инструмента сборки) был включен непосредственно в процесс разработки. Такой подход позволил иметь необходимый срез по библиотекам, которые действительно используются в продукте. А также с его помощью можно проверять, что библиотеки попадают в продукт только из артифактория и не хранятся где-то еще (в коде проекта, на файловых шарах), не скачиваются напрямую из интернета и т.д.
Кроме того, это позволило нам выявить несколько проектов, которые собирались в обход основного артифактория и также содержали зависимости с высоким уровнем критичности, поскольку их мало кто обновлял.
После внедрения данного подхода на большинство команд, уровень использования библиотек с уязвимостями снизился практически в половину от изначального значения, то есть еще 25% от 100 тысяч потенциальных точек проникновения в систему было устранено.
При создании подобного процесса (как и любого другого в рамках безопасной разработки), стоит учитывать, что количество участников может быть очень велико, и все они - из разных подразделений. Как минимум, будут участвовать такие отделы компании:
И стоит понимать, что участие такого количества подразделений может на корню убить всю инициативу, потому что мало просто найти уязвимости в библиотеках, необходимо их еще и устранить, обновить библиотеки, проверить работоспособность и совместимость с текущим кодом и многое другое. Ведь если такой процесс не структурирован и не описан, одновременное присутствие многих специалистов, привыкших решать проблемы, может привести к неразберихе и ухудшению взаимоотношений между сторонами.
Очень важно это понимать и доносить подробности инициативы до всех участников, составив и согласовав полноценное описание всех действий в случае возникновения какого-либо события. Как пример, приведу упрощенный вариант схемы взаимодействия при обнаружении уязвимости в используемой библиотеке, к которому мы пришли после проведения всех предварительных шагов и вычистке самого критичного, что было в приложениях:
Порядок работы с уязвимой компонентой, обнаруженной в процессе анализа используемых библиотек с открытым исходным кодом, можно описать следующим образом:
В приведенном примере работа с уязвимостями и участие в ней каждой стороны описываются прозрачно. Понятно, где зона ответственности отдела разработки, а где - отдела безопасности, а также что происходит при любом варианте развития событий. И все это безотносительно конечного решения, которое будет использоваться. Вместе с тем, мы сразу пониманием, какими особенностями должен обладать не только инструмент, реализующий конкретно эту практику, но и связанные с ним. В данном процессе участвуют и решения для статического анализа, и системы защиты, вроде WAF.
Подобный описанный и согласованный со всеми участниками процесс позволил сократить количество уязвимостей в используемых OpenSource библиотеках в более чем в два раза и полностью избавиться от уязвимостей критического уровня.
А вот еще отличный пример работы с Open Source-библиотеками с пониманием того, что именно используется в сервисах и каких версий. Развитием практики также стала постановка релизных версий на мониторинг. Если кратко, то это работает так: перед развертыванием новой версии приложения на промышленную среду необходимо повторно пройти процедуру проверки и составления перечня используемых в итоговой версии библиотек и их версий, но не только с целью проверки на уязвимости, но и с целью их запоминания и сохранения. Результатом такого «сканирования» является полный список компонент с версиями, которые на данный момент работают у на продуктивной среде. Это необходимо для осуществления регулярного мониторинга появления новых уязвимостей в уже используемых версиях компонент.
Представим, что мы закончили большую функциональность, устранили уязвимости в библиотеках, выкатили новую версию и забыли про этот сервис на несколько месяцев. Можно не сомневаться, что через некоторое время (даже если продукт был безопасным во время релиза) найдутся уязвимости, в том числе и критические, в тех библиотеках, что были использованы. И узнаем мы о них только после того, как снова проведем анализ на предмет наличия проблем. Как раз для того, чтобы сразу их выявлять и своевременно выпускать обновления или принимать компенсирующие меры, необходим процесс постоянного контроля за тем, что используется в продуктивной среде.
Мы прямо наблюдали опасность в действии у одного из наших заказчиков, когда вышла очередная критическая уязвимость в struts2 и сразу после новости, как это обычно бывает, на всевозможные Web-сервисы пошла атака. У него порядка 500 различных сервисов, каждый из которых разрабатывается независимо друг от друга. В отсутствии грамотно выстроенного процесса безопасной разработки, часть которого мы описали выше, в таком разнообразии и количестве невозможно определить, используется ли где-то опасная библиотека и уязвимой ли она версии.
В самом негативном сценарии (как оно обычно и бывает), отдел ИБ массово рассылает письма с просьбой проверить наличие библиотеки, пишет скрипты для анализа репозиториев и всячески пытается найти тот самый сервис, который может быть подвержен этой уязвимости. Но, если у клиента, как это было в нашем случае, работает процесс мониторинга, то все, что нужно сделать – это посмотреть в почту, не пришло ли сообщение о появлении новой уязвимости в любом из наших сервисов. Или, для успокоения совести, проверить, есть ли уязвимая версия в перечне компонент, работающих на данный момент в продуктивной среде. Очень полезная и важная функция, как показала практика, особенно в последнее время.
Если описывать это в цифрах, то в первом варианте (когда процесс не выстроен) при усердной работе найти уязвимый сервис можно за 4-5 рабочих дней, в то время как при грамотном подходе на это уйдет несколько минут. А сколько атак могут реализовать злоумышленники за время простоя? И хотя бы одна из них наверняка окажется успешной, и этого будет достаточно, чтобы парализовать бизнес, если не уничтожить его.
Практика анализа библиотек с открытым исходным кодом позволяет быстро и качественно повысить уровень защищенности разрабатываемого программного обеспечения. А правильно выстроенный процесс будет полезен всем участникам и поможет избежать потерь и стресса при появлении новых критичных уязвимостей. Дополнительно это также позволит соблюсти лицензионную чистоту вашего продукта.
Сбалансированная диета для серого вещества