Безопасность зависимостей и supply chain
Современный фронтенд-проект имеет сотни, а иногда и тысячи транзитивных зависимостей. Каждая из них — чужой код, который выполняется в вашем приложении. История последних лет — от event-stream до xz utils — показала, что supply chain-атаки реальны и разрушительны. Статья систематизирует векторы атак (компрометация мейнтейнера, typosquatting, вредоносные новые версии), инструменты защиты (npm audit, Snyk, Socket, Dependabot, Renovate), lock-файлы, SBOM, provenance и приватные registry.
Содержание
- Что такое supply chain attack
- Как зависимости становятся угрозой
- Известные инциденты
- npm audit и аналоги
- Lock-файлы: почему они важны
- Snyk, Socket и другие инструменты
- SBOM: Software Bill of Materials
- Provenance и reproducible builds
- Приватные registry и ограничение источников
- Чек-лист безопасности зависимостей
- Терминология
- Ключевые тезисы для интервью
- Заключение
- Полезные ссылки
Что такое supply chain attack
Supply chain attack — это атака на цепочку поставок ПО. Злоумышленник не ломает ваше приложение напрямую. Вместо этого он внедряет вредоносный код в один из компонентов, которые вы используете: npm-пакет, библиотеку, инструмент сборки, образ Docker, GitHub Action.
Аналогия: вместо того чтобы взламывать замок вашего дома, злоумышленник подменяет поставщика дверных ручек. Вы устанавливаете новую ручку, а в ней уже есть микрофон и передающее устройство.
В современном фронтенде supply chain особенно уязвима: проект среднего размера легко имеет сотни и тысячи транзитивных зависимостей.
Как зависимости становятся угрозой
Компрометация аккаунта мейнтейнера
Если у разработчика пакета украли пароль от npm, злоумышленник может опубликовать вредоносную версию от его имени.
Тайком переданный доступ
Мейнтейнер устал поддерживать пакет и передал права незнакомцу, который оказался злоумышленником.
Вредоносный код в новой версии
Легитимный мейнтейнер внезапно добавляет в пакет майнер, шифровальщик или скрипт для кражи данных.
Транзитивные зависимости
Вы устанавливаете пакет A, который зависит от B, который зависит от C. C может быть вредоносным, даже если A и B чистые.
typosquatting
Пакеты с именами, похожими на популярные: loadsh вместо lodash, react-domm вместо react-dom. Разработчик ошибается при установке и получает вредонос.
Известные инциденты
ua-parser-js (2021)
Популярный пакет для определения User-Agent. Аккаунт мейнтейнера был скомпрометирован, в версии был добавлен вредоносный код, который скачивал майнер и трояна. Пакет скачивали более 13 миллионов раз в неделю.
colors (2022)
Мейнтейнер намеренно внес бесконечный цикл и странный вывод в пакет colors и faker в знак протеста против коммерческого использования. Это не была кража данных, но показала, насколько хрупок supply chain.
event-stream (2018)
Злоумышленник получил права на пакет и добавил код, который крал биткоины из приложений, использующих Copay.
xz utils (2024)
Хотя это не JavaScript, это один из самых громких supply chain инцидентов. В популярную библиотеку сжатия был внедрён бэкдор на уровне build-скриптов. Показал, что угроза реальна для любого ПО.
npm audit и аналоги
Все основные пакетные менеджеры имеют встроенный аудит:
# npm
npm audit
npm audit --audit-level=high
# pnpm
pnpm audit
# yarn
yarn audit
Эти команды сравнивают ваши зависимости с базой данных известных уязвимостей (основанной на GitHub Advisories) и показывают:
- уровень серьёзности;
- CVE-идентификатор;
- затронутые версии;
- рекомендации по исправлению.
Автоматизация в CI/CD
# .github/workflows/security.yml
name: Security Audit
on: [push, pull_request]
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- run: npm ci
- run: npm audit --audit-level=high
Если audit находит уязвимости уровня high/critical, CI падает и PR не мержится.
Ограничения npm audit
- Проверяет только известные CVE.
- Не анализирует поведение пакета (нет ли шпионского кода без CVE).
- Может давать ложные срабатывания.
Lock-файлы: почему они важны
package-lock.json, pnpm-lock.yaml, yarn.lock фиксируют точные версии всех зависимостей, включая транзитивные.
Почему это важно для безопасности
Без lock-файла npm install может установить более новую версию зависимости, чем та, которую вы тестировали. Если злоумышленник опубликует вредоносную версию, она попадёт в сборку.
Lock-файл гарантирует, что на всех окружениях (dev, CI, production) устанавливаются одинаковые версии.
Правила
- Всегда коммитьте lock-файлы.
- Используйте
npm ci/pnpm install --frozen-lockfileв CI/CD. - Регулярно обновляйте зависимости осознанно, а не случайно.
Snyk, Socket и другие инструменты
Snyk
- Сканирует зависимости на известные уязвимости.
- Может автоматически создавать PR с обновлениями.
- Поддерживает SCA (Software Composition Analysis).
- Есть бесплатный тариф для open-source.
Socket
Анализирует не только CVE, но и поведение пакетов:
- обращается ли пакет к сети;
- читает ли файлы за пределами своей директории;
- использует ли obfuscation;
- добавляет ли shell-скрипты в install-хуки.
Socket помогает находить угрозы, у которых ещё нет CVE.
Dependabot
Встроен в GitHub. Автоматически создаёт PR для обновления зависимостей с известными уязвимостями.
Renovate
Альтернатива Dependabot с бóльшим количеством настроек и поддержкой монорепозиториев.
npm/package签名
С 2024 года npm активно продвигает provenance и подпись пакетов. Подписанные пакеты позволяют проверить, что пакет был собран из конкретного исходного кода на доверенной платформе.
SBOM: Software Bill of Materials
SBOM — это «ингредиенты» вашего приложения: полный список всех зависимостей и их версий.
Форматы
- SPDX — стандарт Linux Foundation.
- CycloneDX — популярен в безопасности.
Генерация
# npm
npm sbom --sbom-format=spdx-json
# cyclonedx
npx @cyclonedx/cyclonedx-npm --output-file=sbom.json
Зачем нужен
- Быстро ответить на вопрос «затронуты ли мы уязвимостью X?».
- Передавать заказчикам и аудиторам.
- Соответствовать требованиям SOC2, NIST, EO 14028.
Provenance и reproducible builds
Provenance
Provenance (происхождение) — это метаданные, подтверждающие, что пакет был собран из конкретного коммита в конкретном репозитории на доверенной CI-платформе.
npm поддерживает provenance для пакетов, опубликованных через GitHub Actions. Это позволяет пользователям проверить:
- откуда взялся пакет;
- кто его собрал;
- не был ли он подменён.
npm publish --provenance
Reproducible builds
Reproducible build — это сборка, которая даёт идентичный результат при повторном запуске. Если сборка воспроизводима, легче обнаружить, что кто-то подменил артефакты.
В JavaScript-мире полностью воспроизводимые сборки сложны, но lock-файлы и фиксированные версии инструментов — первый шаг.
Приватные registry и ограничение источников
Приватный registry
Крупные компании используют приватные npm-регистри (Verdaccio, Nexus, Artifactory), чтобы:
- контролировать, какие пакеты доступны;
- кэшировать внешние пакеты;
- публиковать внутренние пакеты;
- сканировать пакеты перед использованием.
.npmrc
# Разрешаем устанавливать только из доверенных источников
registry=https://registry.npmjs.org/
@mycompany:registry=https://npm.mycompany.com/
Ограничение пакетов
Некоторые инструменты позволяют запретить установку пакетов по критериям:
- возраст пакета;
- количество мейнтейнеров;
- наличие скриптов postinstall;
- наличие зависимостей от заблокированных пакетов.
Чек-лист безопасности зависимостей
Регулярно
- Запускать
npm audit/pnpm audit. - Обновлять зависимости через Dependabot/Renovate.
- Просматривать security advisories для ключевых фреймворков.
В процессах
- Коммитить lock-файлы.
- Использовать
npm ci/--frozen-lockfileв CI. - Настроить CI-проверку
npm audit --audit-level=high. - Использовать Snyk, Socket или аналог для мониторинга.
При добавлении новых зависимостей
- Проверить популярность, возраст и активность пакета.
- Посмотреть исходный код, если пакет маленький.
- Проверить, есть ли скрипты
postinstall. - Избегать typosquatting — проверять имя пакета.
Для compliance
- Генерировать SBOM.
- Использовать пакеты с provenance, где возможно.
- Вести реестр одобренных зависимостей.
Терминология
| Термин | Значение |
|---|---|
| Supply chain attack | Атака через цепочку поставок ПО |
| Transitive dependency | Зависимость зависимости |
| CVE | Common Vulnerabilities and Exposures — идентификатор уязвимости |
| SCA | Software Composition Analysis — анализ состава ПО |
| Lock-file | Файл с фиксированными версиями зависимостей |
| SBOM | Software Bill of Materials — список компонентов ПО |
| Provenance | Доказательство происхождения пакета |
| Reproducible build | Сборка, дающая идентичный результат |
| Typosquatting | Регистрация имён, похожих на популярные пакеты |
| Postinstall script | Скрипт, выполняемый при установке пакета |
Ключевые тезисы для интервью
- Supply chain attack — внедрение вредоносного кода через компонент цепочки (npm-пакет, GitHub Action, Docker-образ); векторы: компрометация мейнтейнера, typosquatting, вредоносные новые версии, транзитивные зависимости.
- Реальные инциденты (
ua-parser-js,event-stream,colors,xz utils) показали, что даже мейнтейнер доверенного пакета может стать угрозой. npm auditпроверяет известные CVE через GitHub Advisories; Socket анализирует поведение пакетов (сеть, файлы, obfuscation,postinstall) и находит угрозы без CVE.- Lock-файлы фиксируют точные версии;
npm ci/--frozen-lockfileв CI гарантирует воспроизводимость; SBOM (SPDX, CycloneDX) — список ингредиентов для быстрого ответа на уязвимости. - Provenance подтверждает, что пакет собран из конкретного коммита на доверенной CI (
npm publish --provenance); приватные registry (Verdaccio, Nexus) позволяют кэшировать, сканировать и ограничивать источники. - При добавлении зависимости проверяйте: возраст, популярность, активность мейнтейнеров,
postinstall-хуки, имя (typosquatting).
Заключение
Supply chain — один из самых серьёзных рисков современного фронтенда. Вы не контролируете все тысячи строк кода в node_modules, но можете контролировать процессы: регулярный аудит, lock-файлы, сканирование через Snyk/Socket, ограничение источников через приватные registry. Инциденты последних лет — от event-stream до xz utils — показали, что даже мейнтейнер годами доверенного пакета может стать угрозой. Для SOC2 и CASA важно показать регулярный аудит зависимостей, процесс реагирования на уязвимости, использование SBOM и контроль над поставщиками ПО. Установка npm-пакета — не безобидное действие, а принятие чужого кода в свой проект.