Защита определяемой пользователем функции javascript для защиты сервера node.js

Я делаю веб-страницу для обучения математике (бэкэнд NodeJS и интерфейс Angular). Я хочу, чтобы особый тип пользователей (создатель) создавал математические упражнения. Одно из этих упражнений может выглядеть так:

Marie has ${nums[0]} oranges and ${nums[1]} apples. How many fruits does she have?

Теперь я хочу, чтобы создатель написал функцию генерации чисел следующим образом:

const generate = () => {
  const nums = new Array(2).fill(0).map(e => Math.floor(Math.random() * 10)
  return { nums: nums, answer: nums.reduce((p, c) => p + c, 0) }
}

Эта функция должна быть отправлена ​​на сервер и сохранена. Когда пользователь хочет попробовать тест, вопрос должен быть выполнен на сервере. Что мне делать, чтобы защитить сервер от вредоносного кода, такого как:

const generate = () => {
  process.exit()
}

Для этого созданы несколько модулей Sandbox. Например: вм2

Mark 06.04.2019 21:13

@MarkMeyer Спасибо за советы. vm2 не поддерживает ограничения памяти. Я тестирую питбосс-нг, и он отлично работает.

Konrad Linkowski 10.04.2019 11:31
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
2
125
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Очень короткий ответ, это никогда не бывает безопасно для сервера. Невозможно доказать, что программа безопасна. Существуют меры по смягчению последствий, такие как песочница, которые помогают, но в конечном итоге это всегда риск. Для этого приложения, возможно, ненужный.

Рассмотрите способ передачи формулы, который не требует exec. Одним из способов может быть отправка какого-либо абстрактного синтаксического дерева или анализ математического выражения.

Этот пакет npm кажется многообещающим. Заполните шаблон строки математического выражения так же, как вы заполняете шаблон письменного вопроса. Может потребоваться предоставить другой объект, чтобы определить, какие случайные числа необходимы, и сопоставить их с именами для использования в шаблонах. math-expression-evaluator

Проблема с математическим выражением в том, что мне нужна относительность переменных. Допустим, вопрос такой: "У Карлы, Алекса и Камиллы x конфет. Они хотят разделить конфеты поровну, чтобы у каждого из них было одинаковое количество конфет. Сколько конфет должен взять каждый из них?" Проблема с такого рода упражнениями в том, что количество людей должно без напоминания делиться на х. сложно вычислить это по математической формуле (я даже не говорю о генераторе случайных имен). Возможно, я просто не знаю, как им правильно пользоваться.

Konrad Linkowski 07.04.2019 10:07

@Konowy Возможно, когда вы определяете случайные значения, позволяете запускать выражение для них во время генерации. В этом примере это может быть как {name:'apples' 'type:'int', min:2, max:20, exp:'2*rand'}.

trognanders 07.04.2019 23:00

Тогда шаблон проблемы может быть "Carla, Alex and Camille have ${apples} apples.[...]". Выражение ответа будет ${apples} / 2.

trognanders 07.04.2019 23:03

Еще одна полезная функция может заключаться в том, чтобы позволить создавать именованные случайные значения из ранее сгенерированных, например: {name:'sticks' type:'calc', exp:'5*apples'}. Таким образом, было бы легко определить значения, которые имеют отношения математических выражений друг к другу.

trognanders 07.04.2019 23:05

Возможно, еще один ответ может состоять в том, чтобы реализовать какой-то сервис запуска кода в чем-то вроде AWS Lambda с достаточно ограниченными разрешениями IAM. Это перенесет основные проблемы с изоляцией на продукт с не твоя проблема.. В этом случае обязательно установите хорошие тайм-ауты и разумные ограничения на использование для каждого пользователя. Используйте отдельную учетную запись AWS, если другие службы размещены на AWS, они гарантируют разделение между учетными записями как минимум на уровне виртуальных машин.

trognanders 07.04.2019 23:08

@Konowy Я сделал больше комментариев, кроме того, в котором я отметил тебя, но забыл отметить другие. Надеюсь поможет?

trognanders 07.04.2019 23:12

Спасибо за очень полезные советы. Время покажет лучшее решение. Я вернусь, когда это будет сделано.

Konrad Linkowski 10.04.2019 11:29

Это не будет безопасно для сервера/клиента.

Не уверен, что это правильный путь или нет. но вы можете ограничить доступ к глобальным переменным

const generate1 = () => {
    process.exit();
}

const generate2 = () => {
    const nums = new Array(2).fill(0).map(e => Math.floor(Math.random() * 10));
    return {
        nums: nums,
        answer: nums.reduce((p, c) => p + c, 0)
    }
}

const funcStr1 = generate1.toString();
const funcStr2 = generate2.toString();

//get all global variables key from 'global' and check it exist or not
// const globals = Object.keys(global); // will return same result as below remove keys which you want to allow
const globals = ['DTRACE_NET_SERVER_CONNECTION',
    'DTRACE_NET_STREAM_END',
    'DTRACE_HTTP_SERVER_REQUEST',
    'DTRACE_HTTP_SERVER_RESPONSE',
    'DTRACE_HTTP_CLIENT_REQUEST',
    'DTRACE_HTTP_CLIENT_RESPONSE',
    'COUNTER_NET_SERVER_CONNECTION',
    'COUNTER_NET_SERVER_CONNECTION_CLOSE',
    'COUNTER_HTTP_SERVER_REQUEST',
    'COUNTER_HTTP_SERVER_RESPONSE',
    'COUNTER_HTTP_CLIENT_REQUEST',
    'COUNTER_HTTP_CLIENT_RESPONSE',
    'global',
    'process',
    'Buffer',
    'clearImmediate',
    'setImmediate',
    // 'clearInterval',
    // 'clearTimeout',
    // 'setInterval',
    // 'setTimeout'
];

const hasGlobal1 = globals.some((g) => funcStr1.includes(`${g}.`));
const hasGlobal2 = globals.some((g) => funcStr2.includes(`${g}.`));

console.info('generate1 has global', hasGlobal1);
console.info('generate2 has global', hasGlobal2);

Использование глобальных переменных может быть лишь одним из случаев, а как насчет бесконечных циклов или чрезмерного потребления памяти?

Yair Nevet 06.04.2019 22:03

@YairNevet это правда, я упомянул This will not be safe for the server. единственную глобальную переменную, которую вы можете ограничить.

Rahul Sharma 06.04.2019 22:05

то, что я упомянул, небезопасно ни для сервера, ни для клиента

Yair Nevet 06.04.2019 22:08

Ваш ответ - это то, что я рассматривал ранее, но он не работает должным образом, потому что Array.prototype.includes также может перехватывать строки и пользовательские переменные. Я думал скорее перезаписать все глобальные переменные перед выполнением и переназначить их снова после этого. Как сказал @YairNevet, бесконечные циклы - большая проблема.

Konrad Linkowski 07.04.2019 10:14

Другие вопросы по теме