Риски установки пакетов с похожими именами: типосквоттинг, атаки на цепочку поставок и защита зависимостей

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

Содержание
  1. Суть проблемы: почему похожие имена работают
  2. Основные виды атак через имена пакетов
  3. Типосквоттинг (typosquatting)
  4. Комбосквоттинг (combosquatting)
  5. Атаки на цепочку поставок (dependency confusion / namespace confusion)
  6. Хакинг имен (name squatting / brandjacking)
  7. Атаки через область видимости (scope confusion)
  8. Как вредоносный код попадает в выполнение
  9. Реальные инциденты: что уже случалось
  10. Как обнаружить подозрительный пакет до установки
  11. Ручные проверки
  12. Автоматизированные инструменты обнаружения
  13. Защита на уровне процесса и конфигурации
  14. 1. Lock-файлы и фиксация версий
  15. 2. Отключение или ограничение install-скриптов
  16. 3. Настройка приоритета реестров (защита от dependency confusion)
  17. 4. Хеширование зависимостей (hash pinning)
  18. 5. Использование приватных прокси-реестров
  19. 6. Политики ревью новых зависимостей
  20. 7. Минимизация поверхности атаки
  21. Пошаговый план: что делать, если подозреваете компрометацию
  22. Сценарии выбора защиты под разные условия
  23. Типичные ошибки, которые приводят к инцидентам
  24. Что делать дальше: чек-лист внедрения защиты
  25. Ответы на частые вопросы
  26. Можно ли полностью автоматизировать защиту от типосквоттинга?
  27. Помогает ли npm audit fix от типосквоттинга?
  28. Стоит ли блокировать все install-скрипты навсегда?
  29. Как защититься, если атака пришла через транзитивную зависимость?
  30. Что такое SLSA и Sigstore, и нужны ли они мне?

Суть проблемы: почему похожие имена работают

Менеджеры пакетов (npm, pip, Maven, Cargo, Go modules, NuGet и другие) разрешают зависимости по строковому имени. Если имя запрошенного пакета совпадает с именем в реестре — менеджер скачивает и устанавливает именно его. Проверки семантического соответствия, репутации автора или соответствия исходному коду репозиторию по умолчанию не выполняются.

Атакующий регистрирует имя, которое визуально или фонетически близко к популярному пакету, и публикует туда вредоносный код. Разработчик, опечатавшись при установке или скопировав имя из ненадёжного источника, подключает вредоносную зависимость. В более сложных сценариях атака направлена на внутренние частные пакеты организации через публичные реестры (dependency confusion).

Основные виды атак через имена пакетов

Типосквоттинг (typosquatting)

Регистрация имён, отличающихся от популярных пакетов опечатками, пропуском или добавлением символов, перестановкой букв, заменой похожих символов (l вместо 1, 0 вместо o). Примеры паттернов:

  • Пропуск символа: reqests вместо requests, expresss вместо express
  • Дублирование: webpck вместо webpack, reactt вместо react
  • Перестановка: beautifulsop4 вместо beautifulsoup4
  • Замена похожих символов: pytnon, nummpy, djnago
  • Ошибки клавиатурной раскладки: githib, npmjs вместо github, npm

Комбосквоттинг (combosquatting)

Добавление значимых слов к имени популярного пакета: requests-security, lodash-utils, react-native-bridge, aws-sdk-extra. Такие имена выглядят как легитимные расширения или официальные модули экосистемы.

Атаки на цепочку поставок (dependency confusion / namespace confusion)

Организации часто используют приватные реестры для внутренних пакетов под именами вроде @company/utils, company-auth, internal-logger. Если в публичном реестре (npm, PyPI) никто не зарегистрировал такое имя, атакующий может это сделать. При неправильной конфигурации приоритета реестров менеджер пакетов может скачать публичный вредоносный пакет вместо приватного.

Хакинг имен (name squatting / brandjacking)

Регистрация имён известных брендов, фреймворков или инструментов до того, как их зарегистрируют официальные владельцы: google-analytics, microsoft-teams, kubernetes-client, docker-compose (в реестрах, где официальные пакеты имеют другие имена).

Атаки через область видимости (scope confusion)

В экосистемах с поддержкой скоупов (npm @scope, PyPI namespaces) атакующий регистрирует пакет в похожем скоупе: @babel/core → @babbel/core, @types/react → @type/react, @angular/core → @anguler/core.

Как вредоносный код попадает в выполнение

Просто установить пакет недостаточно — код должен выполниться. Основные векторы запуска:

  • Скрипты установки (install scripts): в npm — preinstall, install, postinstall в package.json. Выполняются автоматически при npm install.
  • Скрипты сборки: хуки компиляции, генерации кода, пост-обработки.
  • Импорт при разработке: разработчик импортирует модуль в коде — выполняется топ-уровневый код модуля.
  • Entry points / bin-скрипты: пакет объявляет исполняемые команды, которые могут быть вызваны из CI/CD или вручную.
  • Обфускация в исходном коде: вредоносный код маскируется под легальную логику и срабатывает при определённых условиях (время, переменные окружения, наличие файлов).

На практике чаще всего используются postinstall скрипты, которые скачивают и запускают второй этап полезной нагрузки, крадут переменные окружения, SSH-ключи, токены CI/CD, историю браузера или шифруют файлы.

Реальные инциденты: что уже случалось

Публично известные случаи демонстрируют масштаб проблемы. Несколько представительных примеров (не исчерпывающий список):

  • event-stream (npm, 2018): популярный пакет передали новому мейнтейнеру, который добавил вредоносный код, нацеленный на кошельки Copay. Затронуто миллионы загрузок.
  • ua-parser-js, coa, rc (npm, 2021): компрометация аккаунтов мейнтейнеров, публикация версий с майнерами и стиллерами.
  • PyPI: более 4500 вредоносных пакетов (2022–2023): кампании типосквоттинга под requests, django, awscli, azure с обфускированным кодом эксфильтрации данных.
  • Dependency confusion (2021): исследователь Алексей Буткин показал, как публичные пакеты с именами внутренних библиотек Apple, Microsoft, PayPal, Tesla, Uber и других автоматически устанавливались в их CI/CD из-за приоритета публичного реестра.
  • colors.js и faker.js (npm, 2022): автор намеренно сломал свои пакеты, затрагивая тысячи зависимых проектов — пример риска одиночного мейнтейнера.
  • malicious PyPI packages mimicking «pytest», «selenium», «boto3» (2023–2024): использование GitHub Actions для обхода детектирования, загрузка полезной нагрузки с внешних серверов.

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

Как обнаружить подозрительный пакет до установки

Ручные проверки

  • Имя пакета: сравните символ в символ с официальным именем из документации или репозитория владельца.
  • Автор и мейнтейнеры: проверьте профиль в реестре — дата регистрации, количество пакетов, связь с официальной организацией (верифицированный email, домен, GitHub-организация).
  • Репозиторий исходного кода: ссылка на GitHub/GitLab/Bitbucket в метаданных пакета. Откройте — соответствует ли код опубликованному пакету, есть ли теги релизов, история коммитов, issues, PR.
  • Статистика загрузок: аномально низкое количество загрузок для «популярного» пакета — признак подделки. Аномально высокое — может говорить о недавней атаке.
  • Дата публикации: свежий пакет с именем старой известной библиотеки — подозрительно.
  • Файлы пакета: в npm — npm pack —dry-run или просмотр через unpkg.com/jsdelivr. Проверьте наличие postinstall скриптов, бинарных файлов, обфусцированного кода, внешних запросов.
  • Лицензия: отсутствие лицензии или нестандартная — повод для внимания.

Автоматизированные инструменты обнаружения

Инструмент Экосистема Что проверяет
npm audit / yarn audit npm Известные уязвимости в зависимостях (CVE), не типосквоттинг напрямую
Socket.dev (CLI, GitHub app) npm, PyPI, Go, Maven Статический анализ пакетов: install-скрипты, обфускация, сетевые запросы, доступ к fs, env, eval, новые мейнтейнеры, типосквоттинг
Snyk (CLI, IDE, CI) npm, PyPI, Maven, Gradle, NuGet, Go, Cargo Уязвимости, лицензии, вредоносный код в зависимостях
OSS Index / Sonatype Maven, npm, NuGet, PyPI, Go, Cargo Уязвимости, качество компонентов
pip-audit / safety PyPI Уязвимости в Python-зависимостях
Dependabot / Renovate Все основные Автоматические PR для обновлений, может блокировать уязвимые версии
Sigstore / cosign / SLSA Все (подпись артефактов) Верификация происхождения и неизменности пакета
typosquat-checker / similar-package-names npm, PyPI Поиск похожих имён среди установленных зависимостей

Рекомендуемый подход: комбинировать несколько слоёв. npm audit / pip-audit — базовый уровень в CI. Socket или Snyk — глубокий статический анализ новых и обновляемых зависимостей. Dependabot/Renovate — поддержание актуальности. Sigstore/SLSA — верификация происхождения для критических зависимостей.

Защита на уровне процесса и конфигурации

1. Lock-файлы и фиксация версий

Всегда коммитьте package-lock.json, yarn.lock, pnpm-lock.yaml, Pipfile.lock, poetry.lock, go.sum, Cargo.lock. Они гарантируют воспроизводимость сборки и защищают от подмены пакета при повторной установке (если атакующий не компрометировал именно ту версию, что в лок-файле).

2. Отключение или ограничение install-скриптов

  • npm: npm install —ignore-scripts или настройка ignore-scripts=true в .npmrc. В CI — обязательно.
  • pnpm: pnpm install —ignore-scripts (по умолчанию не запускает скрипты зависимостей).
  • yarn: yarn install —ignore-scripts.
  • pip: у pip нет прямых аналогов, но можно использовать —no-build-isolation с осторожностью и проверять pyproject.toml на наличие [tool.setuptools] с cmdclass.

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

3. Настройка приоритета реестров (защита от dependency confusion)

  • npm: используйте .npmrc с явным указанием скоупов для приватного реестра: @mycompany:registry=https://private-registry.example.com/ и @mycompany:always-auth=true. Публичный реестр не должен использоваться для скоупов организации.
  • PyPI: pip.conf с [global] extra-index-url — осторожно, порядок приоритета не гарантирован. Лучше использовать —index-url для приватного и —extra-index-url только для известных публичных пакетов, либо инструменты вроде pip-compile с хешами.
  • Maven: settings.xml с mirrorOf для перенаправления запросов к внутреннему репозиторию (Artifactory, Nexus).
  • Go: GOPRIVATE, GONOSUMDB, GOPROXY для контроля источников модулей.

4. Хеширование зависимостей (hash pinning)

  • npm: npm install —package-lock-only + npm ci использует хеши из lock-файла. Можно добавить integrity проверки вручную.
  • pip: pip install —require-hashes -r requirements.txt с хешами в файле зависимостей (генерируются pip hash или poetry lock/pip-tools).
  • Cargo: Cargo.lock содержит хеши, cargo fetch —locked проверяет их.

Хеши защищают от подмены содержимого пакета при неизменном имени и версии (компрометация реестра или MITM).

5. Использование приватных прокси-реестров

Разверните Artifactory, Nexus, Verdaccio, devpi или используйте управляемые сервисы (GitHub Packages, GitLab Package Registry, AWS CodeArtifact, JFrog). Настройте их как единственный источник зависимостей для CI/CD и разработчиков. Проксируйте публичные реестры с кэшированием, сканированием и политиками блокировки подозрительных пакетов.

6. Политики ревью новых зависимостей

  • Любая новая зависимость — через PR с обязательным ревью безопасности.
  • Проверка: необходимость пакета, популярность, активность репозитория, лицензия, размер, нативные модули, install-скрипты.
  • Автоматические проверки в CI: Socket, Snyk, npm audit, линтеры зависимостей.
  • Запрет на добавление зависимостей без lock-файла и хешей.

7. Минимизация поверхности атаки

  • Избегайте микрозависимостей (однострочники вроде is-odd, left-pad).
  • Аудит devDependencies — они попадают в CI/CD и могут выполнять код при сборке.
  • Регулярный аудит неиспользуемых зависимостей (depcheck, npm-check, pip-autoremove, cargo machete).

Пошаговый план: что делать, если подозреваете компрометацию

  1. Немедленно изолируйте окружение. Остановите CI/CD пайплайны, отзовите токены деплоя, переверните секреты (AWS keys, Docker registry tokens, npm tokens, GitHub PATs, SSH keys), которые могли быть доступны в сборочном окружении.
  2. Идентифицируйте вектор. Проверьте package-lock.json / yarn.lock / Pipfile.lock на предмет подозрительных пакетов. Сравните с package.json / requirements.txt — есть ли лишние зависимости? Используйте npm ls , pip show —files .
  3. Проанализируйте код подозрительного пакета. Скачайте tarball (npm pack, pip download —no-deps), распакуйте, проверьте package.json на scripts, исходники на eval, Function, require(‘child_process’), fetch, axios, обфускацию, строки с base64, обращения к переменным окружения.
  4. Проверьте артефакты сборки. Если пакет выполнялся в CI — проверьте логи на предмет сетевых соединений, записи файлов, запуска процессов. Просканируйте собранные образы (Docker, JAR, wheel) на наличие индикаторов компрометации (IOC).
  5. Оцените масштаб утечки. Какие секреты были доступны в окружении, где выполнялась установка/сборка? Переверните все: облачные ключи, токены реестров, базы данных, ключи шифрования, сертификаты.
  6. Удалите пакет и очистите кэш. Удалите из lock-файла, node_modules, ~/.npm, ~/.cache/pip, ~/.cargo, ~/.m2. Переустановите зависимости из чистого состояния.
  7. Зафиксируйте инцидент. Добавьте имя пакета в внутренний блок-лист прокси-реестра. Сообщите в реестр (npm: npm report / abuse@npmjs.com, PyPI: admin@pypi.org, Maven Central: central@sonatype.com).
  8. Проведите постмортем. Как пакет попал в проект? Какая защита сработала или не сработала? Обновите политики и CI-проверки.

Сценарии выбора защиты под разные условия

Ситуация Рекомендуемый набор мер
Малый проект, один разработчик, нет CI Lock-файл в репозитории, npm install —ignore-scripts / pip install —require-hashes, ручная проверка новых пакетов на GitHub, периодический npm audit / pip-audit
Команда 5–20 человек, есть CI/CD Приватный прокси-реестр (Verdaccio / Nexus / Artifactory), Dependabot/Renovate, Socket.dev или Snyk в CI, обязательный PR-ревью для новых зависимостей, ignore-scripts в CI, хеши в lock-файлах
Enterprise, много репозиториев, строгие требования compliance Централизованный Artifactory/Nexus с политиками блокировки, SBOM (Syft, CycloneDX), подпись артефактов (Sigstore/cosign), SLSA Level 2+ для критических компонентов, внутренний каталог одобренных пакетов, регулярные аудиты, обучение разработчиков
Open-source библиотека, много контрибьюторов Lock-файл в репозитории, npm publish —access restricted для скоупов, 2FA для npm-аккаунтов мейнтейнеров, Dependabot, CodeQL / Socket в CI, подпись релизов, документация по безопасному вкладу

Типичные ошибки, которые приводят к инцидентам

  • Копирование команды установки из блога/StackOverflow/чата без проверки имени. Всегда сверяйтесь с официальной документацией или репозиторием.
  • Игнорирование предупреждений npm audit / pip-audit. Они не идеальны, но базовый слой фильтрации.
  • Хранение секретов в переменных окружения CI без ротации и ограничения области действия. Утечка токена npm/GitHub/AWS через вредоносный postinstall — частый сценарий.
  • Использование npm install в CI вместо npm ci. npm ci требует точного соответствия lock-файлу и не запускает произвольные скрипты обновления.
  • Отсутствие приватного реестра для внутренних пакетов. Прямая зависимость от публичного npm/PyPI для приватных скоувов — открытая дверь для dependency confusion.
  • Добавление зависимостей «на будущее» или «на всякий случай». Каждая зависимость — поверхность атаки.
  • Полное доверие к популярности пакета (звезды на GitHub, загрузки). Популярные пакеты компрометируют через аккаунты мейнтейнеров (event-stream, ua-parser-js) или через транзитивные зависимости.

Что делать дальше: чек-лист внедрения защиты

  1. Включите ignore-scripts в CI для всех менеджеров пакетов.
  2. Настройте приватный прокси-реестр и сделайте его единственным источником для CI и разработчиков.
  3. Добавьте в CI статический анализ зависимостей (Socket.dev, Snyk или аналоги).
  4. Внедрите политику: новая зависимость — только через PR с прохождением проверок.
  5. Настройте Dependabot/Renovate для автоматических обновлений с авто-мержем только для patch-версий после прохождения тестов и аудита.
  6. Переведите все проекты на npm ci / pip install —require-hashes / cargo fetch —locked.
  7. Заведите процесс ротации секретов и аудит доступа к CI/CD переменным.
  8. Обучите команду распознаванию типосквоттинга: практическое упражнение — найти подделку среди 5 похожих имён.
  9. Подготовьте инцидент-респонс план для компрометации зависимости (см. пошаговый план выше).

Ответы на частые вопросы

Можно ли полностью автоматизировать защиту от типосквоттинга?

Нет. Автоматизация (Socket, Snyk, линтеры имён) ловит 90–95% известных паттернов и подозрительного поведения кода. Но целевые атаки с качественной имитацией легального пакета, долгой «спячкой» или компрометацией легального мейнтейнера требуют человеческого ревью, подписи артефактов (Sigstore) и доверия к цепочке поставок (SLSA).

Помогает ли npm audit fix от типосквоттинга?

Нет. npm audit проверяет известные CVE в версиях зависимостей. Типосквоттинг — это установка *другого* пакета с *другим* именем, у которого может не быть CVE. audit fix обновляет версии уже установленных пакетов, не удаляет ошибочно установленные.

Стоит ли блокировать все install-скрипты навсегда?

В CI — да, обязательно. Локально у разработчиков — можно разрешить для пакетов, требующих нативной сборки (node-gyp, rust, go), но только после проверки исходного кода скриптов. Альтернатива: предустановленные бинарные артефакты через приватный реестр.

Как защититься, если атака пришла через транзитивную зависимость?

Lock-файл фиксирует весь дерево. Статический анализ (Socket, Snyk) сканирует транзитивные зависимости. Политика ignore-scripts в CI блокирует выполнение скриптов транзитивных зависимостей. Минимизация зависимостей и замена больших деревьев на легкие альтернативы снижает риск.

Что такое SLSA и Sigstore, и нужны ли они мне?

SLSA (Supply-chain Levels for Software Artifacts) — фреймворк уровней зрелости безопасности цепочки поставок. Sigstore (cosign, Fulcio, Rekor) — инструментарий для подписи и верификации артефактов без управления ключами. Если вы поставляете артефакты (Docker-образы, JAR, wheel, npm-пакеты) для использования другими — внедрение SLSA Level 2+ и подпись релизов через Sigstore существенно повышает доверие потребителей. Для внутренних проектов — по мере зрелости процессов.

Материал носит информационный характер и не заменяет профессионального аудита безопасности или консультации со специалистом по информационной безопасности при выборе и внедрении защитных мер для конкретной инфраструктуры. Упомянутые инструменты и практики отражают общепринятые подходы на момент написания; их эффективность зависит от конфигурации, угрозовой модели и актуальности настроек.

Главный принцип: безопасность зависимостей — это не разовая настройка, а непрерывный процесс. Lock-файлы, приватные реестры, отключение скриптов установки в CI, статический анализ новых пакетов и культура ревью зависимостей вместе создают защиту, в которой ошибка в одной букве не приводит к компрометации инфраструктуры. Начните с внедрения приватного прокси-реестра и ignore-scripts в CI — это даёт наибольший эффект при минимальных затратах.

PEFile.ru