Как запустить Javascript с помощью Rhino для Java в «песочнице»?
-
01-07-2019 - |
Вопрос
Часть нашего Java-приложения должна запускать JavaScript, написанный не разработчиками.Эти не-разработчики используют JavaScript для форматирования данных.(В основном простая логика и конкатенация строк).
Мой вопрос заключается в том, как я могу настроить выполнение этих сценариев, чтобы убедиться, что ошибки сценариев не оказывают серьезного негативного влияния на остальную часть приложения.
- Необходимо защититься от бесконечных циклов
- Остерегайтесь создания новых тем.
- Ограничить доступ к сервисам и среде
- Файловая система (Пример:Если недовольный сценарист решил удалить файлы)
- База данных (то же самое, что и удаление записей базы данных)
По сути, мне нужно настроить область javascript так, чтобы она включала только то, что им нужно, и не более того.
Решение
Чтобы защититься от бесконечных циклов, вам придется поместить его в отдельный процесс, чтобы его можно было завершить.
Чтобы защититься от создания потоков, вам необходимо расширить SecurityManager (реализация по умолчанию позволяет ненадежному коду получать доступ к группам потоков, не являющимся корневыми).
Безопасность Java позволяет предотвратить доступ к файловой системе.
Для ограничений базы данных вы можете использовать стандартную защиту пользователя SQL, но она довольно слаба.В противном случае вам необходимо предоставить API, обеспечивающий соблюдение ваших ограничений.
Редактировать:Я должен отметить, что в версии Rhino, поставляемой с JDK6, была проведена работа по обеспечению безопасности, но в нее не включен компилятор.
Другие советы
Чтобы избежать бесконечных циклов, вы можете наблюдать за количеством инструкций во время выполнения сценария (это работает только с интерпретируемыми сценариями, а не с скомпилированными).
Есть это пример в JavaDocs Rhino чтобы предотвратить запуск скрипта более десяти секунд:
protected void observeInstructionCount(Context cx, int instructionCount)
{
MyContext mcx = (MyContext)cx;
long currentTime = System.currentTimeMillis();
if (currentTime - mcx.startTime > 10*1000) {
// More then 10 seconds from Context creation time:
// it is time to stop the script.
// Throw Error instance to ensure that script will never
// get control back through catch or finally.
throw new Error();
}
}
Чтобы заблокировать доступ к классам и методам Java, посмотрите...
http://codeutopia.net/blog/2009/01/02/sandboxing-rhino-in-java/
Я только что наткнулся на этот пост в блоге, который кажется полезным для более или менее песочницы чего угодно (не только Rhino):
http://calumleslie.blogspot.com/2008/06/simple-jvm-sandboxing.html
Если вам нужны только чистые функции JavaScript, вот решение на основе встроенной библиотеки Rhino JDK без импорта каких-либо сторонних библиотек:
- Узнайте имя класса фабрики движка сценариев JavaScript с помощью ScriptEngineManager#getEngineFactories
- Загрузите класс фабрики механизма сценариев в новый загрузчик классов, в котором JavaMembers или другие связанные классы будут игнорироваться.
- Вызовите #getScriptEngine на загруженной фабрике обработчика сценариев и проверьте сценарии на возвращенном обработчике сценариев.
Если данный сценарий содержит сценарий Java, загрузчик классов попытается загрузить JavaMembers или другие классы и вызвать исключение «Класс не найден».Таким образом, вредоносные скрипты будут игнорироваться без выполнения.
Пожалуйста, прочитайте файлы ConfigJSParser.java и ConfigJSClassLoader.java для получения более подробной информации:
https://github.com/webuzz/simpleconfig/tree/master/src/im/webuzz/config
Javascript является однопоточным и не имеет доступа к файловой системе, поэтому я не думаю, что вам стоит об этом беспокоиться.Я не уверен, есть ли способ установить тайм-аут для защиты от бесконечных циклов, но вы всегда можете создать поток (Java), который выполняет сценарий, а затем завершить поток через столько времени.