Всем привет! В прошлом посте мы начали рассматривать важный вопрос о безопасности в npm и поговорили о том, какие меры использует сама компания для выявления и предотвращения угроз. В этот раз я хочу поговорить об инструментах и подходах, доступных лично вам, и которые я настоятельно рекомендую внедрить в свою практику всем разработчикам. Команда npm install поддерживает ряд скриптов (например: preinstall, install/postinstall), которые могут выполняться в процессе установки пакета. При этом содержимое таких скриптов ничем не ограничивается и выполняется от лица пользователя, выполняющего установку. Такие скрипты являются одним из основных способов для злоумышленников влезть в компьютер, на котором устанавливается вредоносный пакет, и похитить важную информацию. Пример пакета, содержащего вредоносный скрипт:  Если пользователь выполнит команду установки пакета из примера выше: npm install malicious-package, то это приведет к выполнению скрипта evil.sh, который потенциально может совершить любые действия от лица текущего unix-пользователя. Слава богу, в настоящее время npm на своей стороне выполняет статический и поведенческий анализ всех пакетов, публикуемых в npm с целью выявления подобных атак, что должно существенно ограничивать эту угрозу. Однако не стоит полностью списывать ее со счетов. Если у вас есть существенные причины не доверять устанавливаемому пакету, то вы можете запретить выполнение скриптов установки при помощи следующей команды: Также, вы можете полностью запретить выполнение скриптов установки при помощи следующей команды (или добавить настройку в .npmrc): Но учтите, что некоторые пакеты используют скрипты установки для собственной инициализации и не будут корректно работать при установке с запретом на запуск скриптов. Такую практику стоит использовать только в том случае, если у вас есть очень серьезные на то причины.  Чтобы дополнительно обезопасить себя от подобных атак, постарайтесь максимально ограничить среду, в которой выполняются команды npm, такие как npm install. Как вариант, их можно выполнять внутри Docker-контейнера, на виртуальной машине или в любой другой песочнице с ограниченным доступом. Разумеется, никогда не стоит запускать npm от лица root-пользователя; наоборот, лучше запускать эти команды от лица пользователя с минимальным доступом и набором прав. Антивирусы и брандмауэры также могут сократить риски. Принцип прост: чем меньше полномочий получит процесс npm, тем безопаснее будет его работа. Также полезно будет настроить систему предупреждений: если вдруг процесс начнет совершать какие-то подозрительные действия, то вам следует об этом знать. Выявление угрозы безопасности поможет не только вам и вашей команде или компании, но и всему сообществу в целом. Поэтому не забудьте составить и отправить отчет о найденной уязвимости в npm.  Первое правило при работе с ключами доступа и токенами: никогда не храните их в открытом доступе, если этого можно избежать. К примеру, не стоит хранить токен npm в файле .npmrc на вашей машине, если можно аутентифицировать в интерактивном режиме. Если вам всё же необходимо использовать токен аутентификации npm в каком-то автоматическом конвейере (например, для CI/CD), то ограничьте его полномочия. Например, если токен нужен только для установки пакетов из приватного репозитория, то создавайте его в режиме read-only, чтобы в случае его утечки злоумышленник не мог отправить вредоносный код в ваш репозиторий. Это позволит ограничить масштаб угрозы. Также хорошей практикой является привязка токена аутентификации npm к определенному диапазону IP-адресов (CIDR). Закажите себе статический IP (или серию IP) и привяжите его к своему серверу. Как правило, любой облачный провайдер позволяет это сделать, даже если ваш сервер запускается по запросу (on-demand). Таким образом, если злоумышленник сможет украсть токен, то он не сможет использовать его с другой машины. Не размещайте токен аутентификации в файле .npmrc, и тем более не добавляйте его в систему контроля версий (Git). Вместо этого используйте переменную окружения NPM_TOKEN в связке со специальным защищенным хранилищем для токенов (изучите документацию вашего провайдера). Сгенерировать новый токен можно при помощи команды npm token create, которая опционально принимает следующие аргументы: Также рекомендуется регулярно проводить аудит всех токенов, привязанных к npm-аккаунту, и отзывать ненужные. Посмотреть список всех токенов можно в личном кабинете на сайте npm, либо при помощи команды npm token list.  Учтите, что аутентификация при помощи команды npm adduser приравнивается к созданию токена и сохранению его в файле .npmrc в домашней директории пользователя. Удаление же токена приведет к разлогиниванию пользователя. Аутентификация в файле ~/.npmrc выглядит следующим образом: Если вы используете различные независимые npm registry, то таких строк может быть несколько. Что касается закрытых ключей шифрования (например, для SSH), то убедитесь, что они защищены сильным паролем и используют надежный алгоритм шифрования. В случае компрометации такого ключа злоумышленник не сможет им воспользоваться, т. к. не знает пароль, а методы математического взлома окажутся неэффективными. В случае с SSH, в настоящее время алгоритм EdDSA считается наиболее надежным. Однако стоит учесть, что старые системы могут его не поддерживать. Тогда используйте два ключа: Ed25519 (EdDSA) для всех совместимых систем и RSA (с минимум 2048 битным ключом) для устаревших систем.  Одним из старейших приемов в рукаве злоумышленников является использование названий, похожих на оригинальные, но отличающихся одним или несколькими символами. Пользователи часто совершают опечатки при вводе тех или иных названий. Особенно это критично при вызове команды, например, npm install packae-name: в лучшем случае это приведет к ошибке 404, а в худшем — может вызвать вредоносный код. Команда npm старается автоматически вычислять попытки подобного подлога и блокировать пакеты, которые выдают себя за другие. Вам же, как пользователю, следует просто внимательнее относиться к вводу названий пакетов с клавиатуры, по возможности пользуйтесь функцией copy-and-paste.  Про правила использования безопасных паролей сказано уже очень много, не вижу смысла повторяться, однако отмечу основные моменты: Для решения всех вышеописанных вопросов стоит использовать специальное ПО: менеджер паролей. Я использую открытый KeePass (есть версии практически для любой платформы). Базу данных паролей стоит защитить сложным мастер-паролем, который вам необходимо запомнить. Дополнительно можно использовать файл-ключ, который хранится, например, на флешке. Сам же файл базы данных можно положить в любое облачное хранилище (Яндекс.Диск, Google Drive или DropBox), чтобы иметь к нему синхронизированный доступ сразу со всех устройств.  Механизмы мультифакторной аутентификации значительно повышают безопасность вашей учетной записи, т. к. создают дополнительный барьер на пути злоумышленников: даже если кому-то удастся взломать или перехватить ваш пароль, то обойти дополнительный фактор будет гораздо сложнее. При этом стоит обратить внимание именно на использование программ-аутентификаторов и не использовать SMS-сообщения в качестве доп. фактора, т. к. их гораздо проще перехватить. К счастью, npm также поддерживает двухфакторную аутентификацию при помощи программ-аутентификаторов. Она работает в двух режимах: «только аутентификация» или «аутентификация и запись». Лучше всего использовать режим «аутентификация и запись», т. к. это гарантирует самый высокий уровень безопасности, потому что npm будет просить вас ввести токен OTP не только при вызове команды npm adduser, но и при любой попытке записать что-то в реестр (например, при вызове npm publish). О том, как включить npm 2FA, написано подробно в официальной документации. Процесс в целом ничем не отличается от стандартного: вам нужно выбрать режим работы, а затем просканировать QR-код, который будет показан на экране при помощи выбранной вами программы-аутентификатора. Сделать это можно как через личный кабинет на официальном сайте, так и через CLI при помощи команд: При использовании CLI npm попросит вас ввести пароль от аккаунта (даже если вы уже аутентифицированы), а затем покажет QR-код. После сканирования кода нужно ввести одноразовый пароль (OTP), который покажет приложение на устройстве, чтобы подтвердить успешность процедуры. При привязке аутентификатора npm также выдаст вам набор одноразовых кодов восстановления, их необходимо сохранить в надежном месте, на случай, если придется восстанавливать доступ к аккаунту при утере аутентификатора.  Если утеря всё же произошла, вы можете ввести неиспользованный ранее код восстановления вместо одноразового пароля при аутентификации, а затем сбросить 2FA командой npm profile disable-2fa, введя затем еще один код восстановления. Если же вы потеряли и аутентификатор, и коды восстановления, то вам придется обратиться в службу поддержки npm (надеюсь, они защищены от социальной инженерии).  По умолчанию, когда вы выполняете команду npm publish, npm собирает в архив все файлы в директории пакета за исключением некоторых. Часто из-за этого в registry утекают файлы, которые не должны быть опубликованы, например, файлы с паролями. Это серьезная угроза безопасности. Если вы случайно отправили в реестр npm какие-то чувствительные файлы, то вам придется не только удалить архив пакета из реестра, но и полностью заменить все скомпрометированные данные. А чтобы обезопасить себя от подобных утечек, я рекомендую всегда использовать поле files в файле package.json. Оно представляет собой массив, содержащий перечисление файлов (можно использовать шаблоны glob), которые должны попасть в архив собранного пакета. Такой явный подход гарантирует, что в публичный доступ случайно не утекут какие-то нежелательные файлы. Нужно заметить, что следующие файлы всегда попадают в архив, даже если не перечислены в массиве files: При этом файлы README, CHANGES, LICENSE и NOTICE могут иметь любой регистр символов в названии и расширение. По этой причине важно, чтобы перечисленные выше файлы никогда не содержали чувствительной информации. Чтобы проверить, что же попадет в архив при запуске команды npm publish, можно использовать флаг --dry-run либо команду npm pack --dry-run. Вторая команда, в отличие от первой, пропустит скрипты препаблишинга и сразу попытается собрать архив. Аргумент --dry-run гарантирует, что изменения будут произведены в тестовом режиме только на вашей машине, пакет не будет никуда отправляться, и архив не будет реально создан в файловой системе. В этом посте мы начали рассматривать инструменты и подходы, которыми каждый из нас может пользоваться, чтобы повысить безопасность своего npm-проекта. Я настоятельно рекомендую всегда иметь эти аспекты в виду и внедрить описанные инструменты у себя — в наше сложное время дополнительные меры защиты никогда не будут лишними. В следующем посте я хочу снова вернуться к вопросам безопасности и рассмотреть остальные инструменты, о которых я не успел упомянуть сегодня. Если вам понравился материал, то, пожалуйста, ставьте лайки, подписывайтесь на наш блог и делитесь ссылками с коллегами. Так мы будем понимать, что наша работа востребована и продолжим радовать вас новыми полезными материалами. Если же у вас есть вопросы или желание что-то добавить по теме, то не стесняйтесь оставлять комментарии, я с радостью приму участие в обсуждении и учту ваши пожелания в следующих постах. Все изображения в статье являются собственностью своих авторов или законных правообладателей и используются исключительно в некоммерческих образовательных целях. Web-перфекционист