Комментарии 52
Почему такой флаг до сих пор не введён — неясно.
npm install --ignore-scripts
Как подобные проблемы решаются в других языках, в частности, в Ruby и Python?
Насколько я знаю — да никак. Мир не идеален, дерьмо случается, но в данном случае не так уж часто. Честно говоря и ни разу не столкнулся с вредоносным модулем на практике, хотя уже лет 5 как использую npm. Повышенное внимание к npm в этом контексте обусловленно в первую очередь, его популярностью. Тем не меннее, считаю что автор предложил неплохое решение.
Может быть вместо этого проксировать встроенные модули, в хэндлере try {throw} catch, по стэку смотреть, откуда была вызвана функция и либо разрешать и делать что попрошено, либо пробрасывать исключение наверх… Хотя не, производительность просядет, наверное...
Более того если один внешний модуль подключается их двух точек вашего приложения? — Что произойдет если они укажут разные права?
Вариантом получше видится вызов библиотеки в одной точке приложения, и там же определить права для всех внешних модулей(ну или вообще в отдельном конфиг-файле)
Решение такое: подменяем require, это не проблема, в отдельном конфиг-файле указываем какие модули мокать, и какие у них права, тут можно создать группы прав.
В идеале, требуемые права должны быть в package.json самого пакета, как у приложений в мобильных сторах.
Еще вариант, уровень доверия пакета определять на основе его использования в крупных репозиториях, а уж крупные компании могут и должны позволить себе аудит безопасности.
В идеале, требуемые права должны быть в package.json самого пакета
Разумеется. Потенциальный злоумышленник пусть сам указывает, какие права ему нужны.
Да что же все так привязались к бедному npm. Можно подумать, с другими менеджерами пакетов что-то по другому. Вопрос безопасности решается легко — отсматривай, что ты включаешь, и фиксируй версию. Всё. Не надо делать вид, что у вас там чёрный ящик, который надо ограничивать.
Кстати, автоматические анализаторы пакетов на предмет вредоносного кода уже давно есть, и это тоже нормально, хотя ручной проверки кода ничто не заменит.
Nuget — всё то же самое
Composer — всё то же самое
Maven — то же самое
В последнее время всё больше компонентов используется напрямую с гитхаба — тем более всё то же самое. И это только примеры с тех языков, с которыми я непосредственно работал.
Тут возникает очевидный компромис между богатством экосистемы и её безопасностью. Если каждый пакет будет отсматривать специальные люди, то рост их количества и скорости обновлений будет заметно ограничен производительностью этих людей.
Более того — даже наличие специальных людей не гарантирует, что в пакете случайно не будет функции, которая разнесёт всю систему (привет яндекс диску, один из релизов которого делал rm /rf).
И ещё одна бочка дёгтя в вашу каплю мёда — проверка разрешений никоим образом не гарантирует то, что нельзя некорректно воспользоваться выданными разрешениями. Например, пакету может требоваться доступ к файловой системе для записи логов\картинок\кеша\чего угодно. Естественно, этим можно злоупотребить как угодно. Или, к примеру, вы дали права на внешние коннекты. Получите сразу возможность использования зловреда, который отсылает на левый сервер ваши переменные окружения или что угодно ещё.
Так что такой подход очень вреден — это иллюзия безопасности вместо осознанного принятия рисков и принятия корректных мер по борьбе с ними.
Нужен CORS для NodeJS :-)
Например, пакету может требоваться доступ к файловой системе для записи логов\картинок\кеша\чего угодно.
Но ведь для этого он будет использовать другую библиотеку
Переменные окружения — это process.env, о котором я говорил в посте. Разрешение на них даётся отдельно от разрешения на сеть и отдельно от разрешения на ФС.
Maven — то же самое
Do tell me all about it. С каких пор мавен при притаскивании зависимостей из репозитория выполняет произвольные команды из их pom'ов?
Проблема не только и не столько в командах (настолько "в лоб" хакер вряд ли будет что-то делать), сколько в содержимом зависимостей, которые могут помимо целевого назначения делать всё что угодно. Как пример — недавняя статья по поводу пакета, который переменные оружения отправлял на сервер хакера. Зависимость из мавена может делать это точно так же. И никто по этому поводу почему-то не переживает.
Только в случае java вам надо явно дёрнуть какой-то класс из вредоносной зависимости. В случае проблемы с npm'овскими хуками — вам не нужно дёргать зависимость, всё на pre_install/post_install случится.
Т. е. для атаки в случае java нужно, чтобы атакуемый сам вызвал вредоносный код (прямо или транзитивно), а в случае npm — достаточно, чтобы вредоносный модуль был в DAGе зависимостей. В общем, поверхность атаки различается значительно.
Джавовая библиотека atmosphere, например, отсылает информацию в Google Analytics. В один прекрасный день они могут начать собирать чуть больше информации, а вы и не заметите.
Перечитайте, что я писал выше. В случае java вы должны прямо или транзитивно дёрнуть нужную библиотеку. В случае npm достаточно того, что она просто в дереве зависимостей. Это две принципиально разные вещи:
- потенциально вредоносный код сторонних зависимостей (проблема универсальная, не зависящая от инструментария сборки наблюдается и в java, и в js, и в c++, хоть при использовании централизованных репозиториев, хоть при вендоринге);
- наличие хуков, позволяющих злоумышленнику выполнить произвольный код в процессе резолва/установки зависимостей (и это проблема инструментаб, в частности, npm).
Во-первых, в первом комменте уже написали про -флаг --ignore-scripts, при котором ничего не исполняется. Пропишите этот флаг по дефолту и будет вам счастье.
Во-вторых, в этом треде мы обсуждаем вектор атаки, когда вредоносный код активируется в рантайме. Решение автора статьи защищает именно от этого.
Первый коммент видел, но это решение очень условное, если по умолчанию этот флаг не включен. Кроме того, часть пакетов может поломаться из-за его отключения. Даже если они сделают её включенной по умолчанию и добавят whitelist, то из-за привычки к микропакетам в js-мире поддержка такого whitelist'а будет очень негуманной по ресурсам и большинство забьёт.
Ок, если говорить только в контексте активации в рантайме, то я снимаю свои возражения.
Приведу другой пример в дополнению к вашему: очень популярная библиотека quartz до недавнего релиза при запуске проверяла наличие новых версий и сообщала об этом в логе. Обычно это отключалось через system properties, но в некоторых версиях отключение не работало. Если у вас приложение в закрытом контуре, то такое поведение очень неприятно.
В последней версии от этого таки избавились.
А вы часто устанавливаете зависимости, которые потом никак не используете? Если нет, то разницы никакой.
Я — нет. Я наоборот смотрю пристальным взглядом в mvn dependency:tree -Dverbose=true
и проверяю корректность дерева, фиксирую версии принесённые транзитивно, когда надо, выкашиваю лишнее из транзитивки. Но это не самая распространенная практика.
При использовании вектора через хуки в фейковую зависимость добавляется реальная и, возможно, реэкспорт методов из реальной библиотеки.
При использовании вектора через передачу управления также можно спроксировать всё в реальную библиотеку ниже по дереву зависимостей.
Думаю, все потому что, что идея микромодулей в основном используется только в npm. В pypi, например, так не очень принято.
Таки большие модули отличаются только тем, что вы сразу отказываетесь от идеи проверять, что там внутри: )
Ну и нет — что джава, что PHP приложения сейчас обычно тоже тащат с собой кучу сторонних модулей. Но про это почему-то никто не пишет.
Таки большие модули отличаются только тем, что вы сразу отказываетесь от идеи проверять, что там внутри: )
А еще тем, что большой модуль так просто не напишешь. Поэтому почти за каждым из них стоит какая-то организация или конкретный человек, который поддерживает модуль продолжительное время, поэтому словить все описанные проблемы с такими пакетами довольно сложно. Остается разве что проблема неправильных имен, но тут уже ничего не поделать.
Ну и да, в силу того, что я не очень дружу с документацией, то часто приходится лезть в код и смотреть :)
Тут вопрос скорее в количестве. Редко какой Python проект тянет больше пары десятков зависимостей. Для node.js из-за очень мелкой разбивки средняя на порядок больше. Ситуация с npm ближе к maven, нежели к pip или gems. И в мире джава проблемой сборки уже давно все интересуются, хотя нормального решения вроде не видно.
Не пишут потому что эта проблема уже давно решена. Ну, не на 100%, вряд ли это вообще возможно, но настолько, насколько это практически важно и можно.
Если вы хотите глобального решения — то его не существует. По тривиально простой причине — если у вас библиотека (зависимость) скажем удаляет файл, то на этом уровне нельзя сказать, допустимая это операция, или нет.
А на уровне менеджера пакетов — какой-нибудь Nexus Pro вполне умеет большинство из того, что тут предлагалось. Просто потому, что история подобного софта намного длиннее чем у NPM. Ну т.е. вы будете иметь всю историю зависимостей проекта, со всеми известными для каждой уязвимостями, вы не сможете (если настроить) подключить к проекту зависимость, про которую заведомо известно, что там дырка, и так далее. Этот модуль Nexus по-моему называется firewall.
А дальше — уже нужны не только и не столько технические решения.
Во-первых, судя по этой статье, поддержки import
ждать не скоро. Во-вторых, судя по ней же, paraquire
скорее всего просто не сможет загрузить зависимость с import
. Поэтому просто возникнет новый класс библиотек, которые нельзя загнать под paraquire
Как подобные проблемы решаются в других языках, в частности, в Ruby и Python?
Как уже написали, никак. Там просто нет микромодулей, поэтому данная проблема менее актуальна, так как сложно какому-то ноу-нейм пакету выбраться в топы и быть использованым в куче других пакетов.
Вы не анализировали изменения в быстродействии скриптов с paraquire и без?
Также в текущей реализации вижу проблему внедрения данного решения в существующие проекты, придется править практически всю кодовую базу проекта, патчинг require в одном месте тут выглядит более привлекательным
Ну и напоследок, допустим Ваш пакет станет очень популярным, Вы можете дать гарантии, что пакет достаточно защищен от атак злоумышленников?
Ну элементарно же! Нужно ограничивать права этого пакета другим пакетом для ограничения прав!
Что же касательно самой защиты песочницы, то тут я тоже не абсолют, но код невелик и открыт для аудита. Простенькие трюки вроде (0,eval)(code) не проходят.
Да, разграничение доступа к fs — более чем актуально.
Про патчинг require в одном месте уже идёт обсуждение: github.com/nickkolok/paraquire/issues/1
В любом случае, выглядит годно. Можно чуть более подробный мануал по тому, как тремя командами загнать приложуху в chroot jail?
posix.chroot(process.cwd()) // загоняем программу в chroot рабочей папки
posix.setregid(65534,65534) // задаём группу nogroup
posix.setreuid(65534,65534) // задаём юзера nobody
Сначала ставим папку (у непривелигированного юзера может не хватить прав, и команда зафейлится). Потом ставим ID группы (если сначала поставить UID — лишимся прав на смену GID). И под конец UID. Всё.
Единственная проблема — работает это только из-под рута. Но и просто (из userspace) сделать chroot в папку проекта — тоже хорошая практика. php-fpm только так и загонял, и не раз спасало от шеллов. То-есть, шелл-то в дырявый движок пролезал, но сделать с его помощью в chroot можно было примерно ничего.
Мысль-то хорошая, но вот попытка решать данную проблему (безопасность зависимостей) на уровне менеджера зависимостей не кажется удачной. Каждый должен заниматься своим делом, npm — управлять зависимостями. Ну например, Nexus (который в мире java можно считать аналогом npm) вполне себе умеет заниматься такими вещами, как отслеживать, в каких версиях конкретного пакета нашли уязвимости, и сообщать об этом пользователю.
А решать, что можно разрешить в конкретном приложении, а что нельзя — ну не его это дело. Да и нет у него для этого достаточно информации.
Paraquire, или Перестаньте доверять библиотекам