Как запустить ненадежный код на стороне сервера?
Я пытаюсь запустить ненадежный код javascript в linux + node.js с модулем песочницы, но он не работает, все, что мне нужно, это позволить пользователям писать программы на javascript, которые распечатывают некоторый текст. Никакой другой ввод / вывод не допускается, и должен использоваться только простой JavaScript, никаких других узловых модулей. Если это не реально сделать, какой другой язык вы предлагаете для такого рода задач? Минимальный набор функций, который мне нужен, это математика, регулярные выражения, манипуляции со строками и базовые функции JSON. Сценарии будут работать, скажем, 5 секунд, а затем процесс будет убит, как я могу этого добиться?
10 ответов
Все библиотеки, которые я видел, упоминались в таких вопросах (vm2
, jailed
) пытаются изолировать node
сам процесс. Такие "тюрьмы" постоянно ломаются и сильно зависят от будущих обновлений доnode
стандартная библиотека, чтобы не раскрывать другой вектор атаки.
Альтернативой было бы использование V8::Isolate
класс напрямую. Он предназначен для изоляции JavaScript в Google Chrome иnode
, так что вы можете рассчитывать, что он будет полностью поддерживаться и будет более безопасным, чем вы, я или один из сопровождающих библиотеки когда-либо могли бы сделать. Этот класс может запускать только "чистый"JavaScript
. Он имеет полную реализацию ECMAScript, но не имеет API браузера илиnode
API.
Это то, что используется Cloudflare
для своего рабочего продукта.
deno
, новый язык, разработанный node
создатель, по умолчанию стремится к песочнице, используя то же самое и раскрывая части стандартной библиотеки в зависимости от включенных вами флагов.
В node
окружающая среда, вы можете использовать isolated-vm
. Это потрясающая библиотека, которая создаетv8::Isolate
d подпроцессов с кодом, который вы хотите запускать изолированно.
Он предоставляет методы для передачи значений и функций изолированному объекту и обратно. Это не так тривиально в использовании, как большинство библиотек для "тюремного заключения", но гарантирует вам фактическую "песочницу" кода JavaScript.
Поскольку это "чистый" JavaScript, единственные escape-последовательности - это те, которые вы предоставляете в виде внедренных функций.
Кроме того, он автоматически обновляется с каждымnode
версия, поскольку она использует node
собственный v8::Isolate
.
Одна из основных проблем заключается в том, что если вы хотите внедрить библиотеки в свой скрипт, вам, вероятно, потребуется использовать сборщик пакетов, напримерwebpack
чтобы объединить все в один сценарий, который может использоваться библиотекой.
Я лично использую его для запуска кода, предоставленного пользователем, в поисковике для извлечения информации с веб-страницы с использованием кода, предоставленного пользователем, и он творит чудеса.
Недавно я создал библиотеку для песочницы ненадежного кода, кажется, он соответствует требованиям (выполняет код в ограниченном процессе в случае Node.js и в Worker внутри изолированного iframe для веб-браузера):
https://github.com/asvd/jailed
Существует возможность экспортировать данный набор методов из основного приложения в "песочницу", предоставляя любой пользовательский API и набор привилегий (именно эта функция и стала причиной, по которой я решил создать библиотеку с нуля). Упомянутые математические, регулярные выражения и связанные со строками вещи предоставляются самим JavaScript, что-либо дополнительное может быть явно экспортировано извне (например, некоторая функция для связи с основным приложением).
Docker.io - удивительный новичок в блоке, который использует LXC и CGroups для создания песочниц.
Вот одна из реализаций онлайн- гисти (похожая на http://codepad.org/) с использованием Docker и Go Lang
Это просто демонстрирует, что в Docker Containers можно безопасно запускать ненадежный код, написанный на многих языках программирования, включая node.js
Знайте, что уже довольно поздно, чтобы ответить на вопрос, предположите, что приведенный ниже инструмент может быть добавлением стоимости, который не упомянут в ответах / комментариях выше.
Попытка реализовать аналогичный вариант использования. После просмотра веб-ресурсов https://www.npmjs.com/package/vm2 похоже, довольно хорошо справляется со средой песочницы (nodejs).
Он в значительной степени удовлетворяет таким функциям песочницы, как ограничение доступа к встроенным или внешним модулям, обмен данными между песочницей и т. Д.
Основная идея песочниц заключается в том, что для работы нужны переменные, предопределенные как глобальные, поэтому, если вы отрицаете сценарий, отменяя его или заменяя контролируемым, он не может выйти. Пока ты ничего не забудешь.
Сначала замените deny require() или замените его чем-нибудь контролируемым. не забывайте о процессе и "глобальном", то есть "корне", трудно не забыть ничего, поэтому хорошо полагаться на то, что кто-то еще построит песочницу;-)
Если вы можете позволить себе снижение производительности, вы можете запустить JS в одноразовой виртуальной машине с соответствующими ограничениями ЦП и памяти.
Конечно, тогда вы доверяете безопасности решения виртуальной машины. Используя его вместе с обычной песочницей JS, вы получите два уровня безопасности.
Для дополнительного слоя поместите песочницу на физический компьютер, отличный от вашего основного приложения.
Поздний ответ, но, возможно, интересная идея.
Статический анализ кода => AST манипуляции => Генерация кода
- Статический анализ проанализирует AST исходного кода. AST предоставляет общую структуру данных, которая позволяет нам просматривать и изменять исходный код.
- Посредством манипуляций с AST мы можем узнать все ссылки на идентификаторы любых чувствительных переменных во внешних областях. Если нам нужно, мы можем повторно объявить и инициализировать их в начале тела функции, чтобы перезаписать их. Таким образом, ссылки изнутри наружу все под контролем.
- Генерация кодов из AST также проста.
Например, функция как показано ниже:
function () {
a = 1;
window.b = 1;
eval('window.c()');
}
Статический анализ на основе анализатора кода JS позволяет нам вставлять операторы объявления переменных перед исходным телом функции:
function () {
var a, window = {}, eval = function () {}; // variable overwriting
a = 1;
window.b = 1;
eval('window.c()');
}
Вот и все.
Следует рассмотреть возможность перезаписи, например, eval()
, new Function()
и другие глобальные объекты или API. И предупреждения во время разбора должны быть хорошо организованы и сообщены.
Некоторые связанные работы по порядку:
- esprima, инфраструктура парсинга ECMAScript для многоцелевого анализа.
- estraverse, ECMAScript JS AST обходные функции.
- escope, анализатор области видимости ECMAScript.
- escodegen, генератор кода ECMAScript.
Моя практика, основанная на вышеизложенном, - это функция-песочница.
Мы столкнулись с той же проблемой, когда работали над одним из наших продуктов. Мы хотели позволить пользователям предоставлять свой собственный (ненадежный) код, который мы запускали бы при определенных ключевых событиях продукта, например, при выполнении задачи. В значительной степени лучшая альтернатива веб-хукам!
В итоге мы создали отдельный сервис, используя комбинацию AWS Lambda, Rust иV8::Isolate
и некоторые другие элементы, чтобы сделать его не только безопасным, но и очень быстрым. Мы также добавили наши собственные интеграцииfetch()
и тому подобное, поскольку V8 не поддерживает API-интерфейсы, специфичные для Web или Node. Кроме того, это позволило нам делать некоторые полезные вещи, например, ограничивать конечные точки, с которыми может взаимодействовать скрипт, и даже выполнять предварительную аутентификацию запросов путем внедрения предварительно настроенногоAuthorization
заголовок для конкретных запросов/доменов.
Вместо того, чтобы открывать исходный код нашей работы, мы решили предложить эту услугу другим в виде размещенного предложения. Служба развертывается глобально, не требует настройки и по умолчанию не имеет состояния! Вы можете проверить это на https://scriptable.run.
Я сталкиваюсь с подобной проблемой прямо сейчас, и я читаю только плохие вещи о модуле песочницы.
Если вам не нужно ничего специфичного для среды узла, я думаю, что лучшим подходом будет использование безголового браузера, такого как PhantomJS или Chimera, для использования в качестве среды песочницы.
Задайте себе эти вопросы:
- Вы один из самых умных людей на планете?
- Вы регулярно отклоняете предложения о работе от Google, Mozilla и "Лаборатории Касперского", потому что это вам надоедает?
- "Ненадежный код" исходит от людей, работающих в той же компании, что и вы, или от преступников и скучающих компьютерных детей по всему миру?
- Вы уверены, что в node.js нет дыр в безопасности, которые могут просочиться через вашу песочницу?
- Можете ли вы написать идеальный 100% безошибочный код?
- Вы знаете все о JavaScript?
Как вы уже знаете из своих экспериментов с модулем песочницы, написание собственной песочницы не тривиально. Основная проблема с песочницами заключается в том, что вы должны все сделать правильно. Одна ошибка полностью разрушит вашу безопасность, поэтому разработчики браузеров ведут постоянную борьбу с хакерами по всему миру.
Тем не менее, простые песочницы довольно легко сделать. Во-первых, вам нужно написать собственный интерпретатор JavaScript, потому что вы не можете использовать тот из node.js из-за eval()
а также require()
(оба позволят взломщикам сбежать из вашей песочницы).
Интерпретатор должен убедиться, что интерпретируемый код не может получить доступ ни к чему, кроме нескольких глобальных символов, которые вы предоставляете. Это означает, что не может быть eval()
функция, например (или вы должны убедиться, что эта функция оценивается только в контексте вашего собственного интерпретатора JavaScript).
Недостаток этого подхода: много работы, и если вы допустите ошибку в вашем переводчике, взломщики могут покинуть "песочницу".
Другой подход - очистить код и запустить его с помощью node.js. eval()
, Вы можете очистить существующий код, запустив над ним кучу регулярных выражений, например: /eval\s*[(]//g
удалить части вредоносного кода.
Недостаток этого подхода: легко совершить ошибку, которая сделает вас уязвимым для атаки. Например, может быть несоответствие между тем, что regexp и что node.js считают "пробелами". Некоторые неясные пробелы в юникоде могут быть приняты интерпретатором, но не регулярным выражением, которое позволит злоумышленнику выполнить eval()
,
Мое предложение: напишите небольшой демонстрационный тестовый пример, который покажет, как модуль песочницы сломан и исправлен ли он. Это сэкономит вам много времени и усилий, и если в песочнице будет ошибка, это не будет вашей ошибкой (ну, по крайней мере, не совсем).