npm audit fix что это
Безопасность npm-проектов, часть 2
Всем привет! В прошлых постах мы поговорили о том, как команда npm обеспечивает безопасность, а также начали рассматривать инструменты, помогающие нам повысить безопасность проектов. Я хочу продолжить разговор и рассмотреть следующий набор полезных инструментов.
npm audit
В позапрошлом посте мы подробно поговорили о том, как команда безопасности npm выявляет угрозы и публикует информацию о них в виде «рекомендаций по безопасности» в специальном реестре.
К счастью, нам не нужно каждый день вручную просматривать все отчеты о найденных уязвимостях, чтобы убедиться, что они не затрагивают наш проект. npm предоставляет набор интегрированных с реестром безопасности инструментов, который позволяет быстро выявлять проблемы в вашем проекте.
При наличии проблем будет выведено примерно такое сообщение:
В примере выше говорится о том, что проект содержит три уязвимости, две из которых имеют высокий уровень опасности.
Помимо автоматической проверки зависимостей на уязвимости в процессе их установки, npm также предоставляет специальную команду для проведения аудита безопасности: npm audit.
При вызове эта команда отправляет данные обо всех зависимостях в вашем проекте в реестр npm, назначенный по умолчанию, для анализа на наличие уязвимостей.
Однако важно заметить, что эти данные npm берет из lock-файла проекта. При отсутствии этого файла npm выдаст ошибку:
Это еще один важный аргумент, почему использование lock-файлов в npm-проекте необходимо.
Давайте теперь рассмотрим пример вывода команды npm audit:
Как мы видим на скриншоте выше, команда выводит список всех замечаний по безопасности, и каждое замечание отображается в виде таблицы, которая содержит:
Как правило, для исправления уязвимостей достаточно обновить проблемный пакет до нужной patch-версии. Однако бывают ситуации, когда исправление доступно только при минорном или мажорном обновлении. Если необходимое обновление нарушает правила semver, указанные в манифесте проекта, то npm audit предупредит об этом, выведя сообщение: « SEMVER WARNING: Recommended action is a potentially breaking change ». После применения таких исправлений вам необходимо выполнить все те же действия, что и при обычном критическом обновлении: изучить журнал изменений зависимости, и, при необходимости, внести правки в код вашего проекта, чтобы устранить возможные нарушения обратной совместимости.
Если же исправление для найденной уязвимости еще не доступно, то npm предложит вам выполнить самостоятельную оценку (Manual Review). В этом случае вам стоит начать с изучения подробной информации об уязвимости на сайте npm.
Возможно, уязвимость воспроизводится только при определенных условиях, которые отсутствуют в вашем проекте. Например, уязвимость проявляется на другой версии операционной системы или при вызове функции, которой вы не пользуетесь и не собираетесь пользоваться. Тогда вы можете просто взять эту информацию на заметку. В противном случае для минимизации риска вам может понадобиться немного переписать свой код.
О важности обновлений
Мажорные изменения зависимостей требуют от разработчика определенного погружения, ручного изучения журнала изменений обновляемого пакета, и, возможно, внесения правок в исходный код проекта, который мог быть затронут этими изменениями. Учитывая большое количество зависимостей в среднестатистическом проекте, многим разработчикам некогда заниматься обновлениями, и они откладывают это в долгий ящик. Они действуют по принципу: раз всё работает, то нет смысла что-то обновлять. К сожалению, такая стратегия в конечном итоге может привести к печальным последствиям. Чем больше мажорных обновлений пропущено разработчиком, тем сложнее впоследствии ему будет обновить проект до последней версии.
А теперь представим ситуацию, когда в пакете, которым пользуется нерадивый разработчик и который он не обновлял уже год, обнаруживается критическая уязвимость безопасности. В таких ситуациях, как правило, счёт идет на часы. После выпуска исправления безопасности (а они, как правило, выпускаются как патчи для последней мажорной версии пакета) об уязвимости становится широко известно всему Интернету, а соответственно и злоумышленникам, у которых появляется возможность использовать уязвимость для атаки на системы, которые пока еще не успели обновиться. Возникает ситуация гонки, когда разработчики торопятся обновить уязвимое ПО, а злоумышленники пытаются воспользоваться уязвимостью, пока она еще не закрыта.
Согласитесь, в такой ситуации разработчику из нашего примера придется очень несладко: мало того, что ему нужно быстро обновить версию зависимости (чтобы опередить злоумышленников), так ему еще нужно выполнить все необходимые миграции, чтобы гарантировать, что мажорные обновления, которые были выпущены за последний год и которые он торжественно пропустил, не сломают проект. А если в проекте еще отсутствуют автотесты, то бессонная ночь будет гарантирована.
По этой причине я еще раз настоятельно рекомендую регулярно обновлять все зависимости проекта до последних версий. Это гарантирует, что в случае выхода критических патчей по безопасности вы сможете обновиться максимально быстро (возможно, даже автоматически) и не дать времени злоумышленникам на то, чтобы развернуть против вас успешную атаку.
Смена мейнтейнера
Ситуация со сменой лица, ответственного за разработку и публикацию какого-нибудь публичного пакета, тоже имеет потенциально опасный характер. В прошлом уже бывали случаи, когда, воспользовавшись методами социальной инженерии, злоумышленники втирались в доверие к разработчикам популярных пакетов и предлагали им взять дальнейшую разработку на себя. В мире Open Source, когда желающих поддерживать библиотеки, как правило, намного меньше, чем желающих просто их использовать, добиться получения прав мейнтейнера не так уж и сложно, особенно при наличии хороших навыков разработки. После получения же прав на публикацию пакета новоиспеченный мейнтейнер в овечьей шкуре внедряет зловредный код в дистрибутив пакета и публикует новую версию, прикрывая это какими-нибудь несложными правками. Ничего не подозревающие разработчики просто скачивают очередное обновление и делают свой проект уязвимым.
Такая атака может быть особенно опасной, и гарантированно защититься от нее сложно; остается надеяться, что сканер уязвимостей не пропустит вредоносный код.
Авторам же пакетов можно посоветовать внимательнее относиться к тем людям, которым они передают управление пакетами, и в случае передачи выпускать новую версию пакета под другим npm-именем, чтобы переход был более очевидным для пользователей.
Следим за уведомлениями
Каждый раз, когда вы публикуете новую версию пакета в реестре npm, система отправляет вам письмо с уведомлением. Я настоятельно рекомендую вывести эти уведомления на первый план, чтобы вы всегда их видели, даже если не находитесь на рабочем месте. Если все предыдущие методы защиты оказались неэффективными и злоумышленник всё-таки смог получить доступ к вашему npm-аккаунту, а затем опубликовать вредоносный пакет, то вы сразу об этом узнаете и сможете принять экстренные меры.
Пишем отчет об уязвимости
Система безопасности npm не была бы столь эффективной, если бы не тысячи разработчиков, постоянно анализирующие код пакетов, с которыми они работают, не находили бы уязвимости самостоятельно и не сообщали бы об этом в npm (см. закон Линуса).
Если вдруг вам посчастливилось обнаружить уязвимость в одном из npm-пакетов, не торопитесь писать об этом на GitHub! Если вы сообщите об уязвимости публично, то эта информация попадет, в том числе, и в руки злоумышленников, которые смогут воспользоваться ей в деструктивных целях. Поэтому правильнее будет отправить отчет об уязвимости напрямую команде безопасности npm. Для этого достаточно зайти на страницу уязвимого пакета на официальном портале npm и нажать на кнопку «Report a vulnerability» (сообщить об уязвимости). Далее необходимо заполнить форму с отчетом, указав в ней всю релевантную информацию.
После получения отчета команда безопасности npm проверит пакет на наличие описанной вами проблемы безопасности, и в случае ее подтверждения свяжется с автором для устранения (либо оперативно примет другие необходимые меры). Подробнее о действиях команды безопасности npm можно прочитать в одной из прошлых статей: «Как npm обеспечивает безопасность».
Что должно быть в отчете?
Чтобы команда безопасности npm могла отреагировать на угрозу максимально оперативно и эффективно, ваш отчет должен содержать четкую и детализированную информацию, на основе которой можно было бы построить дальнейший план действий. В частности, постарайтесь включить в отчет:
При оформлении отчета постарайтесь изолировать проблему до самой ее сути, максимально исключив лишнюю и нерелевантную информацию, которая может усложнить понимание или увести в сторону.
Подписи PGP
Как я уже упоминал ранее, в момент установки зависимости npm скачивает архив пакета из реестра и в обязательном порядке проверяет его контрольную сумму. Это гарантирует, что архив пакета был скачан без ошибок, и в процессе его доставки не произошло сбоев.
Однако если злоумышленнику удастся подменить собой сервер npm, проведя атаку типа «человек посередине», то он сможет:
Скачав такой пакет, клиент не заметит подмены, потому что и архив, и контрольная сумма приходят от злоумышленника.
Чтобы повысить безопасность доставки пакетов до пользователей, команда npm ввела специальный механизм PGP-подписей. PGP — это система асимметричного шифрования (с использованием закрытого и открытого ключей), которая позволяет создавать и проверять цифровые подписи. Работает это следующим образом. Вначале команда npm сгенерировала пару из закрытого и открытого ключа. Затем они опубликовали свой открытый ключ на специальном портале Keybase. Портал выступает как доверенное лицо (authority) и подтверждает для всех пользователей, что опубликованный npm публичный ключ действительно принадлежит компании npm, Inc. Достигается это благодаря социальному подтверждению: если зайти на страницу npm на Keybase, то вы увидите, что к ней привязаны официальный Twitter-канал npm, а также домены npmjs.com и npmjs.org. Закрытый же ключ компания держит в секрете и подписывает им все пакеты, которые публикуются в официальном реестре.
Таким образом, скачав архив пакета из реестра npm, вы можете проверить с помощью публичного PGP-ключа npm из Keybase, что архив не был изменен. Злоумышленник просто не смог бы этого сделать, потому что он не знает закрытого ключа.
Команда npm опубликовала статью с подробным руководством по проверке цифровых подписей PGP. Однако стоит заметить, что хотя этот механизм был введен более двух лет назад, npm CLI до сих пор не проверяет цифровые подписи автоматически. Мне также пока не удалось найти готовых инструментов для этого. Получается, что в настоящее время это можно делать только вручную. Я уже обратился к разработчикам npm за комментариями по этому вопросу и с радостью поделюсь результатами с моими читателями в будущем. На самом деле реализовать такой инструмент не должно быть сложно. Возможно, кто-то из вас захочет взяться за эту интересную задачу и внести свой вклад в повышение безопасности npm.
Продолжение следует
В этом посте мы продолжили рассматривать инструменты и подходы, которыми каждый из нас может пользоваться для повышения безопасности своего npm-проекта. В следующем посте я планирую завершить секцию по безопасности, рассмотрев инструменты, доступные на стороне GitHub.
Если вам понравился материал, то, пожалуйста, ставьте лайки, подписывайтесь на наш блог и делитесь ссылками с коллегами. Так мы будем понимать, что наша работа востребована, и продолжим радовать вас новыми полезными материалами.
Если же у вас есть вопросы или желание что-то добавить по теме, то не стесняйтесь оставлять комментарии, я с радостью приму участие в обсуждении и учту ваши пожелания в следующих постах.
npm audit работает неправильно — это настоящий театр безопасности
Думаю, придётся мне.
npm audit работает принципиально неправильно. Проверка по умолчанию на каждый npm install — поспешный, непродуманный и неадекватный подход.
Слышали историю про мальчика, который часто кричал «Волк!»? Спойлер: в результате волк съел овец. Если мы не хотим такого итога, нам нужны лучшие инструменты.
На сегодняшний день npm audit — это пятно на всей экосистеме npm. Надо было исправить его с самого начала, но лучше поздно, чем никогда.
Как работает npm audit?
Промотайте эту часть, если вы с ней знакомы.
У приложения Node.js есть дерево зависимостей. Оно может выглядеть следующим образом:
Скорее всего, дерево гораздо глубже.
Теперь предположим, что обнаружена уязвимость в network-utility@1.0.0 :
Вот как должен работать npm audit в теории.
Как сказал кто-то мудрый, в теории нет разницы между теорией и практикой. Но разница есть на практике. И вот тут начинается самое интересное.
Почему это неправильный подход
Посмотрим, что происходит на практике. Для тестирования возьмём Create React App. Этот набор включает множество инструментов, в том числе Babel, webpack, TypeScript, ESLint, PostCSS, Terser и другие. Create React App берёт ваш исходный код JavaScript — и преобразует в статичную папку HTML+JS+CSS. Примечательно, что он не создаёт приложение Node.js.
Итак, делаем новый проект!
Сразу после создания проекта видим следующее:
Чёрт побери! В только что созданном приложении уже уязвимости!
Запустим npm audit и посмотрим, что случилось.
Первая «уязвимость»
Вот первая проблема, о которой сообщает npm audit :
Тогда он уберёт из выдачи устаревшие хаки flexbox. Поскольку множество инструментов полагаются на один и тот же формат конфигурации целевых браузеров, Create React App использует общий пакет browserslist для парсинга файла конфигурации.
Итак, я полагаю, что эта «умеренная» «уязвимость» не является ни умеренной, ни уязвимостью в контексте проекта. Проехали.
Вердикт: эта «уязвимость» абсурдна в данном контексте.
Вторая «уязвимость»
Вот следующая проблема, о которой с готовностью сообщил npm audit :
К сожалению, glob-parent уязвим! Если злоумышленник предоставит специально созданный путь к файлу, он может сделать эту функцию экспоненциально медленной, что приведёт к…
Погодите, что?! Сервер разработки находится на вашем компьютере. Файлы находятся на вашем компьютере. Файл-вотчер использует указанную вами конфигурацию. Ни одна из этих конструкций не покидает ваш компьютер. Если злоумышленник достаточно изощрён, чтобы войти на вашу машину во время локальной разработки, последнее, что он захочет сделать, это создать специальные длинные пути к файлам, чтобы замедлить вашу разработку. Так что эта угроза просто абсурдна.
Похоже, что эта «умеренная» «уязвимость» не является ни умеренной, ни уязвимостью в контексте проекта.
Вердикт: эта «уязвимость» абсурдна в данном контексте.
Третья «уязвимость»
Давайте посмотрим на это:
Подождите, это то же самое, что и выше, но через другой путь зависимости.
Вердикт: эта «уязвимость» абсурдна в данном контексте.
Четвёртая «уязвимость»
Уф, выглядит очень плохо! npm audit осмелился показать её красным цветом:
Что это за проблема «высокой» важности? «Отказ в обслуживании»? Я не хочу, чтобы в обслуживании было отказано! Это будет очень плохо… Если только…
Давайте посмотрим внимательнее на проблему. Очевидно, что парсер для CSS-селекторов css-what может замедлиться при получении специально созданных входных данных. Этот парсер используется плагином, который генерирует компоненты React из SVG-файлов.
Это означает, что если злоумышленник получит контроль над моей машиной разработки или моим исходным кодом, он поместит специальный SVG-файл, в котором будет находиться специально созданный CSS-селектор, что сделает мою сборку медленной. Уязвимость проверена и подтверждена…
Подождите, что?! Если злоумышленник может изменить исходный код моего приложения, то просто добавит туда криптомайнер. Зачем добавлять файлы SVG, если только они не майнят монеро? Опять же, в этом никакого смысла.
Вердикт: «уязвимость» абсурдна в данном контексте.
Вот вам и «высокая» важность.
Пятая «уязвимость»
Вердикт: эта «уязвимость» абсурдна в данном контексте.
Продолжать?
Мальчик уже пять раз прокричал «Волк!». Два предупреждения — это дубли. Остальные абсурдны и не имеют значения в контексте использования этих зависимостей.
Пять ложноположительных срабатываний — не так уж плохо.
К сожалению, их сотни.
Вот несколько типичных тредов, есть и много других:
Я потратил несколько часов, но изучил абсолютно все проблемы, о которых сообщил npm audit за последние несколько месяцев, и похоже, что все они являются ложными срабатываниями в контексте такого инструмента для сборки, как Create React App, в виде «набора зависимостей».
Конечно, их можно исправить. Можно ослабить некоторые зависимости верхнего уровня, расширив «фокус» вместо указания конкретных версий (что приведёт к более частому проскальзыванию багов в патчи). Можно участить релизы, чтобы этот театр безопасности никогда нас не догнал.
Но этого недостаточно. Представьте, если б ваши тесты в 99% случаев не срабатывали по надуманным причинам! Это бесполезная трата многих человеко-лет и совершенно лишние проблемы. Причём страдают все категории:
Что делать?
Я не знаю, как решить проблему. Не я её создал, так что не мне решать. Знаю только то, что нынешняя система не работает.
Есть несколько возможных решений.
Нужно что-то делать.
Сейчас npm audit сломан.
Новички, опытные разработчики, мейнтейнеры, отделы безопасности и, самое главное, наши пользователи — заслуживают лучшего.
npm audit работает неправильно — это настоящий театр безопасности
Думаю, придётся мне.
npm audit работает принципиально неправильно. Проверка по умолчанию на каждый npm install — поспешный, непродуманный и неадекватный подход.
Слышали историю про мальчика, который часто кричал «Волк!»? Спойлер: в результате волк съел овец. Если мы не хотим такого итога, нам нужны лучшие инструменты.
Как работает npm audit?
У приложения Node.js есть дерево зависимостей. Оно может выглядеть следующим образом:
Скорее всего, дерево гораздо глубже.
Теперь предположим, что обнаружена уязвимость в network-utility@1.0.0 :
Вот как должен работать npm audit в теории.
Как сказал кто-то мудрый, в теории нет разницы между теорией и практикой. Но разница есть на практике. И вот тут начинается самое интересное.
Почему это неправильный подход
Посмотрим, что происходит на практике. Для тестирования возьмём Create React App. Этот набор включает множество инструментов, в том числе Babel, webpack, TypeScript, ESLint, PostCSS, Terser и другие. Create React App берёт ваш исходный код JavaScript — и преобразует в статичную папку HTML+JS+CSS. Примечательно, что он не создаёт приложение Node.js.
Итак, делаем новый проект!
Сразу после создания проекта видим следующее:
Чёрт побери! В только что созданном приложении уже уязвимости!
Запустим npm audit и посмотрим, что случилось.
Первая «уязвимость»
Вот первая проблема, о которой сообщает npm audit :
Тогда он уберёт из выдачи устаревшие хаки flexbox. Поскольку множество инструментов полагаются на один и тот же формат конфигурации целевых браузеров, Create React App использует общий пакет browserslist для парсинга файла конфигурации.
Итак, я полагаю, что эта «умеренная» «уязвимость» не является ни умеренной, ни уязвимостью в контексте проекта. Проехали.
Вердикт: эта «уязвимость» абсурдна в данном контексте.
Вторая «уязвимость»
Вот следующая проблема, о которой с готовностью сообщил npm audit :
К сожалению, glob-parent уязвим! Если злоумышленник предоставит специально созданный путь к файлу, он может сделать эту функцию экспоненциально медленной, что приведёт к…
Погодите, что?! Сервер разработки находится на вашем компьютере. Файлы находятся на вашем компьютере. Файл-вотчер использует указанную вами конфигурацию. Ни одна из этих конструкций не покидает ваш компьютер. Если злоумышленник достаточно изощрён, чтобы войти на вашу машину во время локальной разработки, последнее, что он захочет сделать, это создать специальные длинные пути к файлам, чтобы замедлить вашу разработку. Так что эта угроза просто абсурдна.
Похоже, что эта «умеренная» «уязвимость» не является ни умеренной, ни уязвимостью в контексте проекта.
Вердикт: эта «уязвимость» абсурдна в данном контексте.
Третья «уязвимость»
Давайте посмотрим на это:
Подождите, это то же самое, что и выше, но через другой путь зависимости.
Вердикт: эта «уязвимость» абсурдна в данном контексте.
Четвёртая «уязвимость»
Уф, выглядит очень плохо! npm audit осмелился показать её красным цветом:
Что это за проблема «высокой» важности? «Отказ в обслуживании»? Я не хочу, чтобы в обслуживании было отказано! Это будет очень плохо… Если только…
Давайте посмотрим внимательнее на проблему. Очевидно, что парсер для CSS-селекторов css-what может замедлиться при получении специально созданных входных данных. Этот парсер используется плагином, который генерирует компоненты React из SVG-файлов.
Это означает, что если злоумышленник получит контроль над моей машиной разработки или моим исходным кодом, он поместит специальный SVG-файл, в котором будет находиться специально созданный CSS-селектор, что сделает мою сборку медленной. Уязвимость проверена и подтверждена…
Подождите, что?! Если злоумышленник может изменить исходный код моего приложения, то просто добавит туда криптомайнер. Зачем добавлять файлы SVG, если только они не майнят монеро? Опять же, в этом никакого смысла.
Вердикт: «уязвимость» абсурдна в данном контексте.
Вот вам и «высокая» важность.
Пятая «уязвимость»
Вердикт: эта «уязвимость» абсурдна в данном контексте.
Продолжать?
Мальчик уже пять раз прокричал «Волк!». Два предупреждения — это дубли. Остальные абсурдны и не имеют значения в контексте использования этих зависимостей.
Пять ложноположительных срабатываний — не так уж плохо.
К сожалению, их сотни.
Я потратил несколько часов, но изучил абсолютно все проблемы, о которых сообщил npm audit за последние несколько месяцев, и похоже, что все они являются ложными срабатываниями в контексте такого инструмента для сборки, как Create React App, в виде «набора зависимостей».
Конечно, их можно исправить. Можно ослабить некоторые зависимости верхнего уровня, расширив «фокус» вместо указания конкретных версий (что приведёт к более частому проскальзыванию багов в патчи). Можно участить релизы, чтобы этот театр безопасности никогда нас не догнал.
Но этого недостаточно. Представьте, если б ваши тесты в 99% случаев не срабатывали по надуманным причинам! Это бесполезная трата многих человеко-лет и совершенно лишние проблемы. Причём страдают все категории:
Что делать?
Я не знаю, как решить проблему. Не я её создал, так что не мне решать. Знаю только то, что нынешняя система не работает.
Есть несколько возможных решений.
Нужно что-то делать.
Сейчас npm audit сломан.
Новички, опытные разработчики, мейнтейнеры, отделы безопасности и, самое главное, наши пользователи — заслуживают лучшего.
Правильный способ исправить потенциальную уязвимость безопасности в зависимости, определенной в package-lock.json
Github выдал мне эту ошибку в одном из моих репозиториев.
Новое: теперь с npm @ 6 вы можете напрямую запускать
Вы должны попытаться определить имя проблемного пакета, а затем запустить
замена имени пакета, очевидно.
При этом будет установлена последняя версия пакета, и очень часто последняя версия устраняет проблему безопасности. Если у вас есть ограничение на версию (например, 1.2), вы всегда можете попробовать:
и будет установлена последняя исправленная версия
Чтобы решить эту проблему:
И наконец: npm install bcrypt @ latest
Затем отправьте обновленный проект в git (т.е. выполните новую фиксацию).
Решение 2:
если первый вариант / решение не решает проблему, измените версию вручную в файле package-lock.json. Измените версию вручную с 2.16.3 на 4.2.1
Затем обновите свой проект на GitHub (фиксация / нажатие). Просто убедитесь, что каждая версия hoek-версии в вашей версии package-lock.json изменена на 4.2.1.
У меня была такая же проблема с уязвимостью безопасности lodash в проекте, который я создавал с помощью пряжи. Github пометил это как проблемы безопасности.
Похоже, что пряжа пытается решить такие проблемы (или не предназначена для этого).
Если у вас возникла эта проблема при сборке с помощью пряжи, попробуйте переключиться [назад] на npm!