Безопасность npm-проектов, часть 2

в 8:01, , рубрики: checksum, javascript, Node, node.js, nodejs, npm, npm-audit, pgp, pgp-signature, security, security audit, security reports, безопасность, Блог компании ДомКлик, информационная безопасность, Разработка веб-сайтов

Безопасность npm-проектов, часть 2

Всем привет! В прошлых постах мы поговорили о том, как команда npm обеспечивает безопасность, а также начали рассматривать инструменты, помогающие нам повысить безопасность проектов. Я хочу продолжить разговор и рассмотреть следующий набор полезных инструментов.

npm audit

В позапрошлом посте мы подробно поговорили о том, как команда безопасности npm выявляет угрозы и публикует информацию о них в виде «рекомендаций по безопасности» в специальном реестре.

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

Например, каждый раз, когда вы выполняете команду npm install, npm дополнительно проводит аудит безопасности, чтобы убедиться, что установленные пакеты не привносят в проект уязвимостей. Рекомендую внимательно относиться к выводу этой команды в консоли. В случае отсутствия проблем в последней строчке должно быть написано:

Безопасность npm-проектов, часть 2 - 2

При наличии проблем будет выведено примерно такое сообщение:

Безопасность npm-проектов, часть 2 - 3

В примере выше говорится о том, что проект содержит три уязвимости, две из которых имеют высокий уровень опасности.

Помимо автоматической проверки зависимостей на уязвимости в процессе их установки, npm также предоставляет специальную команду для проведения аудита безопасности: npm audit.

При вызове эта команда отправляет данные обо всех зависимостях в вашем проекте в реестр npm, назначенный по умолчанию, для анализа на наличие уязвимостей.

Однако важно заметить, что эти данные npm берет из lock-файла проекта. При отсутствии этого файла npm выдаст ошибку:

Безопасность npm-проектов, часть 2 - 4

Это еще один важный аргумент, почему использование lock-файлов в npm-проекте необходимо.

Давайте теперь рассмотрим пример вывода команды npm audit:

Безопасность npm-проектов, часть 2 - 5

Как мы видим на скриншоте выше, команда выводит список всех замечаний по безопасности, и каждое замечание отображается в виде таблицы, которая содержит:

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

Чтобы автоматически устранить все найденные уязвимости, достаточно выполнить команду npm audit fix. Либо вы можете вручную вызвать указанные команды для исправления уязвимостей.

Как правило, для исправления уязвимостей достаточно обновить проблемный пакет до нужной 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 могла отреагировать на угрозу максимально оперативно и эффективно, ваш отчет должен содержать четкую и детализированную информацию, на основе которой можно было бы построить дальнейший план действий. В частности, постарайтесь включить в отчет:

  • точное название уязвимого пакета или пакетов,
  • версию или диапазон версий, которые подвержены уязвимости,
  • краткое описание уязвимости и степень ее опасности,
  • описание окружения, в рамках которого воспроизводится проблема (модель и версия ОС, версия Node.js),
  • описание последовательных шагов для гарантированного воспроизведения проблемы,
  • примеры кода, ссылки или документы, которые могут помочь команде безопасности быстрее понять и лучше разобраться в проблеме.

При оформлении отчета постарайтесь изолировать проблему до самой ее сути, максимально исключив лишнюю и нерелевантную информацию, которая может усложнить понимание или увести в сторону.

За вдохновением можно обратиться к описанию уязвимостей на портале npm.

Подписи PGP

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

Однако если злоумышленнику удастся подменить собой сервер 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.


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

Если же у вас есть вопросы или желание что-то добавить по теме, то не стесняйтесь оставлять комментарии, я с радостью приму участие в обсуждении и учту ваши пожелания в следующих постах.

Автор: Slava Fomin II

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js