Аудит зависимостей и цепочка поставок

Современное JavaScript-приложение, собранное с использованием Webpack, формируется не только из исходного кода разработчика, но и из глубокой транзитивной сети пакетов. Каждый импорт в коде может тянуть за собой десятки и сотни зависимостей, образуя сложный граф поставки (supply chain). Этот граф включает:

  • прямые зависимости (declared dependencies)
  • транзитивные зависимости (dependencies of dependencies)
  • devDependencies, влияющие на сборку
  • peerDependencies, определяющие совместимость
  • optionalDependencies, влияющие на поведение в разных окружениях

Webpack работает поверх этой структуры, превращая её в единый бандл, но не устраняет риски, связанные с цепочкой поставок. Напротив, он делает их менее очевидными, так как конечный результат скрывает исходные источники кода.


Граф зависимостей как объект аудита

Webpack строит внутренний граф модулей, начиная с entry points. Однако этот граф не равен графу npm-зависимостей. Важное различие:

  • граф Webpack — это граф импортов модулей в рантайме сборки
  • граф npm — это граф установленных пакетов в node_modules

Аудит цепочки поставок требует анализа именно npm-графа, включая:

  • глубину зависимостей
  • дублирование пакетов
  • конфликтующие версии
  • скрытые зависимости через require внутри зависимостей

Инструменты вроде webpack --stats позволяют частично визуализировать модульный граф, но не дают полной картины supply chain.


Уязвимости транзитивных зависимостей

Основной риск в JavaScript-экосистеме связан с транзитивными пакетами. Даже если проект напрямую зависит от безопасной библиотеки, она может использовать уязвимые внутренние модули.

Типовые проблемы:

  • внедрение вредоносного кода через компрометированный пакет
  • подмена версии зависимости через диапазоны semver (^, ~)
  • незаметное обновление транзитивной зависимости при установке
  • использование abandonware с накопленными уязвимостями

Особенно опасны случаи, когда пакет с минимальной функциональностью тянет десятки зависимостей без явной необходимости.


Semver как источник нестабильности цепочки поставок

Semantic Versioning в npm является одновременно инструментом гибкости и источником риска. Диапазоны:

  • ^1.2.3
  • ~1.2.3
  • >=1.0.0

позволяют автоматически подтягивать новые версии без изменения package.json.

В контексте supply chain это означает:

  • внезапное появление нового кода после установки
  • невозможность воспроизвести одинаковый node_modules без lockfile
  • риск внедрения вредоносных обновлений в patch/minor релизах

Lockfile как основа детерминированной сборки

Файлы package-lock.json, yarn.lock, pnpm-lock.yaml фиксируют точное состояние графа зависимостей.

Ключевые свойства:

  • фиксируют версии транзитивных зависимостей
  • обеспечивают воспроизводимость установки
  • уменьшают риск непредсказуемых обновлений

Однако даже lockfile не является абсолютной защитой:

  • возможна компрометация registry
  • возможны подмены пакетов при отсутствии integrity checksum
  • устаревший lockfile может содержать уязвимости

npm audit и статический анализ зависимостей

Инструмент npm audit выполняет проверку известных уязвимостей в дереве зависимостей. Он анализирует:

  • CVE базы данных
  • известные уязвимости пакетов
  • диапазоны затронутых версий

Ограничения:

  • не обнаруживает zero-day уязвимости
  • зависит от актуальности базы данных
  • может давать ложные срабатывания
  • не анализирует бизнес-логику вредоносного кода

Дополнительно используются:

  • pnpm audit
  • yarn audit
  • Snyk
  • OSV Scanner

Анализ бандла Webpack как часть аудита

Webpack предоставляет статистику сборки, которая может быть использована для анализа supply chain на уровне бандла.

Основные инструменты:

webpack stats

Файл stats.json включает:

  • список модулей
  • размеры кода
  • зависимости между модулями
  • чанки и их содержимое

Это позволяет выявлять:

  • неожиданные крупные зависимости
  • дублирование библиотек
  • попадание лишнего кода в production bundle

webpack-bundle-analyzer

Графический анализатор бандла позволяет:

  • визуализировать структуру зависимостей
  • выявить «тяжёлые» пакеты
  • обнаружить скрытые зависимости
  • понять вклад каждого модуля

Часто именно здесь обнаруживаются пакеты, добавленные транзитивно, но влияющие на размер и безопасность приложения.


Детектирование скрытых и дублирующихся зависимостей

В supply chain-аудите важна идентификация:

  • одинаковых пакетов разных версий
  • модулей, установленных через разные цепочки
  • скрытых зависимостей внутри node_modules

Инструменты:

  • npm ls
  • yarn why
  • pnpm why

Webpack-ориентированные инструменты:

  • dependency-cruiser
  • madge

Они позволяют строить граф импортов и выявлять:

  • циклические зависимости
  • неиспользуемые модули
  • неожиданные импортные связи

Риски компрометации цепочки поставок

Основные сценарии атак:

Подмена пакета

Злоумышленник публикует новую версию популярного пакета с вредоносным кодом.

Dependency confusion

Внутренние пакеты организации перехватываются публичным registry при неправильной настройке имен.

Typosquatting

Пакеты с похожими названиями используются для обмана разработчиков.

Postinstall scripts

Скрипты установки выполняют код во время npm install, что делает возможным выполнение произвольных действий в системе.

Webpack напрямую не защищает от этих атак, так как они происходят до этапа сборки.


Postinstall и lifecycle scripts как скрытая зона риска

В npm lifecycle scripts:

  • preinstall
  • install
  • postinstall

могут выполняться произвольные команды.

Риски:

  • выполнение вредоносного кода до сборки
  • доступ к файловой системе
  • утечка переменных окружения CI

Практика минимизации риска:

  • использование npm ci вместо npm install
  • отключение scripts в CI (--ignore-scripts)
  • контроль доверенных пакетов

Integrity и проверка целостности пакетов

Современные package-lock файлы содержат integrity-хэши (SHA-512). Они позволяют:

  • проверять целостность скачанного пакета
  • предотвращать подмену содержимого в registry или сети

Но остаются ограничения:

  • не защищает от компрометации самого registry
  • не гарантирует отсутствие вредоносного кода в оригинальном пакете

Webpack и воспроизводимость сборки

Webpack может давать разные результаты при одинаковом коде, если нарушена стабильность зависимостей.

Факторы влияния:

  • нестабильные версии npm пакетов
  • плагины Webpack с динамическим поведением
  • различия в Node.js окружении
  • плагины, генерирующие случайные идентификаторы

Для стабилизации используются:

  • фиксированные версии loaders и plugins
  • lockfile
  • mode: production
  • deterministic module ids

Supply chain на уровне плагинов Webpack

Плагины Webpack имеют высокий уровень привилегий, так как могут:

  • изменять AST кода
  • подменять модули
  • модифицировать output bundle
  • добавлять runtime код

Это делает их критической точкой аудита.

Особенно важно проверять:

  • webpack plugins из неизвестных источников
  • loaders с post-processing логикой
  • инструменты минификации и обфускации

SBOM как инструмент контроля зависимостей

Software Bill of Materials (SBOM) фиксирует полный список компонентов приложения:

  • npm пакеты
  • версии
  • лицензии
  • источники

SBOM позволяет:

  • отслеживать цепочку поставок
  • проводить аудит безопасности
  • быстро реагировать на CVE

Webpack напрямую SBOM не генерирует, но может быть частью pipeline, который формирует SBOM через анализ stats и package-lock.


Контроль лицензий как часть аудита

Supply chain включает не только безопасность, но и юридические риски.

Проблемные сценарии:

  • использование несовместимых лицензий (GPL в коммерческом продукте)
  • скрытые зависимости с restrictive licenses
  • отсутствие лицензий в транзитивных пакетах

Инструменты:

  • license-checker
  • yarn licenses
  • автоматический анализ CI pipeline

CI как точка контроля цепочки поставок

Аудит зависимостей должен быть встроен в CI/CD процесс.

Типовые проверки:

  • npm ci вместо установки из изменяемого дерева
  • npm audit на каждом merge request
  • генерация и сравнение package-lock
  • проверка размера бандла (bundle size regression)
  • анализ stats.json

Дополнительно:

  • запрет установки без lockfile
  • контроль изменений в package.json
  • блокировка неизвестных registry источников

Поведенческий анализ зависимостей

Помимо статического анализа важен поведенческий:

  • сетевые запросы пакетов во время runtime
  • доступ к process.env
  • доступ к файловой системе
  • динамическая загрузка кода

Webpack bundle analyzer не выявляет такие паттерны напрямую, но может помочь обнаружить подозрительные библиотеки по косвенным признакам (например, чрезмерные postinstall скрипты или obfuscated code).


Итоговая модель аудита цепочки поставок

Аудит в Webpack-проектах представляет собой многослойную систему:

  • уровень npm зависимостей (lockfile, semver, audit)
  • уровень файловой системы (node_modules, дубли)
  • уровень сборки (Webpack graph, plugins, loaders)
  • уровень бандла (output, size, content analysis)
  • уровень CI (детерминированность и проверки)

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