Bob: Alice, ты в прошлый раз меня убедила, что мне необходимо проверить свои сторонние зависимости в проекте на риски атак через цепочку поставок (Supply Chain). По итогу уже нашлось три подозрительные библиотеки. Я вообще не понимаю, как они попали в мой проект, их давно пора было заменить нормальным аналогом.
Alice: Отлично, рада слышать! А что это были за библиотеки?
Bob: Одна библиотека не обновлялась с 2018 года, у неё даже в репозитории на GitHub было открыто пару issue с найденными уязвимостями, но, естественно, никто не собирался их исправлять. Я нашёл форк этой же библиотеки, только уже с нормальным активным сообществом и заменил в своём проекте, теперь даже живётся спокойнее. Ещё мне бросился в глаза импорт одной и той же библиотеки: websockts и websockets. Точнее, почти одной и той же, одна из них была с опечаткой. Но ты можешь представить, Alice, несмотря на мою опечатку, проект всё равно стабильно работал!
Alice: Bob! Да ты ведь попался на Typosquatting! Я уверена, что одна из библиотек уязвимая! Ты уже завёл инцидент?
Bob: Да почему сразу уязвимая, ведь всё работало штатно. Я просто исправил опечатку.
Alice: Да ведь так и делают злоумышленники: к абсолютно легитимному функционалу добавляют злонамеренный и выкладывают в пакетный менеджер с незаметной опечаткой. Bob, они могут быть уже внутри твоей инфраструктуры. Я тебе сейчас скину ещё одну статью, там как раз рассказывается об актуальных методах атак на зависимости. Про Typosquatting там тоже есть!
Eva: * !#$@№!*?!% *
Как хорошо заблаговременно задумываться о безопасности Supply Chain и знать об актуальных методах атак на сторонние компоненты! Так подумала Alice, смотря вслед Bob'y. А Eva в этот момент поняла, что, кажется, становится бессильна и теряет последние возможности атаковать проект Bob'а через его зависимости.
Типы атак на ваши зависимости
Статья, которую Alice дала почитать Bob'у
Примечательно, что многие, говоря о безопасности цепочки поставок, подразумевают сам анализ SCA, а кто-то путает Supply Chain attacks с атаками через Trusted Relationship. Кстати, об их различиях хорошо рассказали наши коллеги в другой статье. Но, несмотря на расхождения, в центре внимания безопасность наших зависимостей. Поэтому сильно в терминологию вдаваться не будем и сойдёмся на том, что для нас, разработчиков ПО, безопасность зависимостей — это нечто большее, чем привычный всем SCA, и что нужно не только помнить о потенциальных угрозах эксплуатации CVE, но и быть готовыми к другим атакам на наши зависимости.
Давайте рассмотрим ещё некоторые методы, которые злоумышленники могут использовать для манипуляций с зависимостями. Именно из-за них разработчик или пакетный менеджер может по ошибке скачать вредоносный пакет и даже не заметить.
1. Typosquatting
Механизм. Разработчик делает опечатку во время импорта той или иной библиотеки, и, таким образом, неумышленно скачивает совершенно другой компонент. Эти библиотеки с похожими названиями заранее создают злоумышленники и внедряют туда злонамеренный функционал. Самое страшное, что при работе с такой библиотекой можно даже не заметить подмены, так как весь легитимный функционал также будет присутствовать и стабильно работать.
Например, одна из популярных библиотек в NPM — colors, нужна она для того, чтобы играть с цветами в консоли node.js.
Если разработчик опечатается и вместо colors укажет colorsss, то в проект скачается уже совершенно другая библиотека — злонамеренная:
Иногда Typosquatting разделяют на подкатегории.
● Combosquatting: злоумышленники добавляют общие слова, термины или буквы к оригинальному имени пакета, чтобы имитировать законные пакеты.
o twilio -> twilio-npm
o cross-env -> cross-env.js
o fabric -> node-fabric
o lodash -> lodashs
● Omission: это преднамеренное упущение символа в имени пакета.
o mongoose -> mongose
o babel-cli -> babelcli
o cross-env -> crossenv
● Repetition: повторение символа в имени пакета.
o jquery -> jquerry
● Transposition: изменение местами двух букв в имени пакета.
o http-proxy-middleware -> http-proxy-middelware
o electron -> electorn
Можно было бы также добавить категорию с перестановками, например, разработчик может перепутать написание какого-нибудь react-router с router-react. Кстати, обе библиотеки из нашего примера существуют, но, кажется, не несут угрозы безопасности.
А для самых современных разработчиков, которые используют ChatGPT для поиска библиотек с необходимым функционалом, припасен еще один тип атаки —AI Package Hallucination. Часто AI предлагает разработчику хорошие варианты, но случаются и глюки, когда он выдает имена несуществующих на текущий момент библиотек. Злоумышленник, в свою очередь, может создавать пакеты с именами таких галлюцинаций, чтобы какой-нибудь разработчик скачал и использовал его злонамеренный код.
Примеры реализации: их достаточно много.
Для JavaScript/TypeSript в пакетном менеджере NPM
Для Python в пакетном менеджере PyPi
Для Go подобных инцидентов не так много из-за подхода к наименованию зависимостей (например, github.com/golang/protobuf v1.5.3). Такой подход снижает вероятность путаницы, но, несмотря на это, случаи тоже были.
Для PHP в пакетном менеджере Packagist.
Для Ruby в пакетном менеджере RubyGems. Были даже предприняты попытки со стороны самого RubyGems бороться с Typosquatting. Но видимо, в какой-то момент это начало уже мешать самому Ruby-сообществу, в итоге они извинились и отключили свои алгоритмы.
Для Java, Scala, Kotlin в пакетном менеджере Maven Central подобные атаки реализовать тоже сложнее, но инциденты всё же были.
Для Swift с его Swift Package Index уже придуманы меры безопасности на этапе загрузки нового пакета в репозиторий.
В языках C/C++ чаще появляются коммерческие сторонние библиотеки. У них нет автоматического пакетного менеджера, который бы автоматически импортировал все зависимости. Это, к слову, привело к явлению Not Invented Here (NIH), когда разработчики предпочитают создавать свои собственные решения вместо использования сторонних библиотек.
2. Starjacking
Механизм. Для злоумышленников это скорее вспомогательный инструмент, нежели самостоятельный. Техника актуальна для пакетных менеджеров NPM/Yarn, PyPi и RubyGems и заключается в краже популярности («звёздочек») у чужого известного пакета. Проблема в том, что в названных менеджерах нет проверки связи между пакетом и ссылкой на репозиторий GitHub, которая указывается при публикации. Таким образом можно присвоить себе репутацию любого популярного проекта на GitHub и наслаждаться рейтингом в 100500 звёзд. Такая репутация может создать ложное положительное впечатление о пакете и заставить разработчика воспользоваться такой библиотекой.
Пример. Ниже можно увидеть, как выглядит оригинальная криптографическая библиотека openssl в RubyGems, а также её кастомная реализация openssl_custom. Разработчик openssl_custom решил присвоить себе звёзды оригинального проекта. Умышленно ли он это сделал или нет, нам остаётся лишь догадываться. Но спасибо ему за неплохой пример starjacking.
3. Repojacking
Механизм. Злоумышленник регистрирует репозиторий под хорошо известным именем другого, который был удалён или сменил название. GitHub знает о проблеме и внедрил защитные меры, но исследователи утверждают, что эти решения всё ещё не очень надежны, так как злоумышленники научились их обходить.
Пример реализации. В мае 2022 года так произошло с PHP-пакетом Phpass, владелец которого удалил свою учётную запись. Злоумышленик зарегистрировал учётку с точно таким же именем и получил полный контроль над исходным репозиторием. Имея все права, он дополнил исходный код пакета вредоносом и опубликовал его в Packagist, откуда он впоследствии был скачан пользователями.
Прочитать подробнее о Repojacking можно в статье от AquaSec. Именно они обнаружили, что большое количество репозиториев на Github может быть уязвимо для атак по цепочке поставок на большое количество пользователей, и исследовали эту тему.
4. Dependency Confusion
Механизм. Злоумышленники стараются запутать менеджеры пакетов во время скачивания локальных зависимостей. Для этого они могут загружать в общедоступный репозиторий вредоносный пакет с тем же именем, что и внутренний пакет, используемый организацией. Так можно обманом заставить пакетный менеджер скачать вредоносный компонент. Например, они могут предпочесть вредоносный пакет законному частному, если он имеет более высокий номер версии.
Это ещё один повод для закрепления версий зависимостей в проекте вместо использования latest-версии. Некоторые пакетные менеджеры уже задумались о решении этой проблемы на своей стороне. Так, начиная с версии 2.0 Composer, частные репозитории имеют приоритет над общедоступными. Однако всё ещё остаются и те, кто считает такую функциональность не багом, а фичей.
Пример. Давайте посмотрим на один пакет из пакетного менеджера NPM, который мы нашли во время этого исследования. Само содержимое пакета пока ещё не несёт угроз безопасности. При этом его наименование очень похоже на имя внутреннего пакета компании Pizza Hut, а версия содержит аномально большое число, что, естественно, вызывает вопросы. Будем надеяться, что данный пакет создан внутренними исследователями безопасности компании для тестирования продукта на атаку через Dependency Confusion.
Пробуем на практике
По аналогии с первой частью статьи загрузим SBOM на анализ и посмотрим, как подобные атаки можно выявить, используя автоматизацию. Для этого будем использовать инструмент AppScreener с включённой опцией анализа Supply Chain (SCS). Получаем такой результат.
Пакет ms-react-native получил оценку 0 — очень высокий риск атак через Supply Chain. А все потому, что пакет присвоил себе репутацию популярного проекта https://github.com/facebook/react-native — тип атаки Starjacking. В этом случае все метрики зануляются, так как являются показательными только для истинного пакета.
Если посмотреть на пакет autoprifixir, то можно увидеть не только риск Typosquatting, но и активную важную метрику «библиотека создана недавно». Согласно пункту 3.1.8 CIS Software Supply Chain Security Guidelines, возраст пакета должен быть больше 60 дней: эта мера предосторожности поможет избежать внедрения потенциально вредоносных сторонних пакетов и обеспечить достаточное время на их проверку.
Оба пакета, ms-react-native и autoprifixir, нужно в срочном порядке проверить на истинность всех угроз. В случае с autoprifixir разработчик скорее всего имел в виду библиотеку autoprefixer, поэтому достаточно будет произвести замену. А для ms‑react-native необходимо найти аналог или провести ручной аудит текущего пакета и, приняв все риски, использовать его в своём проекте.
Вывод
О чем задумался Bob после разговора с Alice
Интересно заметить, что для одних языков (например, JavaScript (NPM) или Python (PyPI)), наблюдается большое количество успешных атак на зависимости, а для других (например, для Java (Maven Central)) — единичные случаи. Этот феномен объясняется заложенными принципами и подходами в самих языках программирования.
Например, Sonatype, которая управляет репозиторием Maven Central, требует от разработчика больше усилий при публикации пакетов. Он должен владеть доменом, под идентификатором группы которого он хотел бы создать свой пакет, что, естественно, снижает порог входа. При этом в обширной стандартной библиотеке Java содержится множество базовых функциональностей. Внешние пакеты если и есть, то, как правило, достаточно крупные, полные и самодостаточные. Всё это способствует тому, что количество зависимостей обычно не стремится к бесконечности.
JavaScript, в свою очередь, поощряет множество маленьких зависимостей и не накладывает сложных ограничений на публикацию пакетов в NPM. Это частично связано с тем, что его стандартная библиотека не такая самодостаточная. Большая часть полезного функционала содержится как раз именно в сторонних библиотеках, многие из которых написаны разработчиками в одиночку и могут быть уже давно заброшены.
Это не делает ни один из упомянутых языков хуже или лучше. В каждом подходе есть свои плюсы. Нужно лишь учесть, что разные языки программирования имеют разные подходы к управлению зависимостями, что сильно влияет на экосистему самого языка и на подходы к его безопасности.
Можно укрепиться в выводе, сделанном по итогам прошлой статьи: open source доступен для изменений и обновлений всем, включая потенциальных злоумышленников, что делает внешние зависимости проекта самой уязвимой частью Supply Chain. Важно помнить, что разработчик может опечататься, проглядеть или скачать совершенно не тот пакет из-за неправильной настройки пакетного менеджера. Реализация надежной цепочки поставок — сложная задача, требующая внимания. Иначе однажды, воспользовавшись безобидным на первый взгляд расширением для React, можно получить неприятный сюрприз в виде шифровальщика или утечки чувствительных данных.
Автор: Татьяна Куцовол
ведущий аналитик-исследователь ИБ в ГК «Солар»