Supply Chain Attacks — npm

Supply Chain Attack в контексте npm — атака через компрометацию npm-пакета (злоумышленник захватывает популярный пакет или публикует вредоносный под похожим именем), в результате чего вредоносный код попадает в тысячи проектов.

Зачем нужно

Атака на цепочку поставок позволяет заразить тысячи проектов одним скомпрометированным пакетом. Реальные примеры: event-stream (2018, 2M загрузок/неделя), ua-parser-js (2021, 8M загрузок/неделя), colors.js (2022, намеренное уничтожение).

Где используется

  • Любой Node.js/JavaScript проект с зависимостями из npm
  • CI/CD пайплайны, устанавливающие пакеты при сборке
  • Docker образы с npm install

Основной контент

Типы атак

1. Typosquatting     — пакет с похожим именем (cross-env vs crossenv)
2. Account takeover  — захват аккаунта мейнтейнера, публикация вредоносной версии
3. Dependency confusion — пакет внутренней сети заменяется публичным с более высокой версией
4. Malicious update  — мейнтейнер намеренно добавляет вредоносный код
5. Postinstall hook  — вредоносный код в scripts.postinstall package.json

Защита: package-lock.json() и integrity

# ВСЕГДА коммитить package-lock.json()
# Он фиксирует точную версию И хэш каждого пакета

# npm ci (для CI) — устанавливает строго из lock-файла
npm ci   # Не обновляет lock, завалит при расхождении

# Проверить integrity пакета вручную
npm audit signatures

Защита: проверка скриптов в package.json зависимостей

# Посмотреть postinstall скрипты ПЕРЕД установкой
npm install --dry-run

# Отключить lifecycle scripts (осторожно — может сломать некоторые пакеты)
npm install --ignore-scripts

# Просмотр scripts конкретного пакета
cat node_modules/some-package/package.json | jq '.scripts'

Защита: .npmrc конфигурация

# Запретить установку пакетов с postinstall скриптами без явного разрешения
ignore-scripts=true

# Только конкретный registry (не публичный)
registry=https://registry.npmjs.org/
# Для внутренних пакетов — отдельный scope
@company:registry=https://npm.company.com/

# Проверять integrity всех пакетов
package-lock=true

Dependency Confusion — защита

# Убедиться, что внутренние пакеты публикуются в приватный registry
# И в .npmrc настроен scope для них:
@internal:registry=https://npm.internal.company.com/

# Зарезервировать имена внутренних пакетов на npmjs.com
# (пустой публичный пакет с более низкой версией)

Мониторинг: Socket.dev

# socket — инструмент для анализа новых зависимостей
npm install -g @socketsecurity/cli
socket npm install lodash  # Анализирует пакет перед установкой

Частые ошибки

  • Использование ^ и ~ в production зависимостях без lock-файла — обновление до вредоносной версии
  • Отсутствие npm ci в CI (использование npm install) — игнорирует lock-файл
  • Установка пакетов с --ignore-scripts пропускается разработчиками локально
  • Отсутствие мониторинга npm advisories для уже установленных пакетов

Связанные темы

Ресурсы