Сценарий
Я работаю над кодом Javascript, который позволяет запускать произвольный пользовательский код в среде веб-рабочего, подобный этому подходу. Позвольте позвонить обеим сторонам (запускает рабочего) и гостя (внутри рабочего).
Теперь я хочу иметь возможность одновременно запускать несколько сценариев на рабочем месте или, по крайней мере, сразу же отправлять их работнику, не дожидаясь окончания предыдущего script. Крайне важно уменьшить задержку и накладные расходы, потому что один сеанс может занять миллионы или даже миллиарды script - чем больше я могу сделать за несколько секунд, тем лучше; и да, есть веская причина, почему я выбираю Javascript (производительность важна, но не самый важный аспект).
Однако это означает, что работник как-то должен с уверенностью сказать мне, когда script запущен и остановлен. Это требует некоторой отправки сообщений с уникальным идентификатором script.
Код
В настоящее время я использую этот код в гостевой системе:
onmessage = function(event) {
var scriptId = event.data.id;
var cmd = event.data.cmd;
var args = event.data.args;
switch (cmd) {
case "init":
// code here to lock down the worker and disable everything potentially insecure, except for postMessage
break;
case "run":
if (!workerInitialized()) return;
// run user given code
var code = args.code;
// ...
postMessage({cmd: "start", args: scriptId}); // signal that script started
runScript(code); // runs eval(code) with proper error reporting etc.
postMessage({cmd: "stop", args: scriptId}); // signal that script stopped
break;
// ...
}
}
Проблема
Как вы можете видеть, scriptId
существует в стеке кадра выше eval(code)
. Я использую некоторую криптографическую библиотеку для генерации идентификатора, поэтому пользователь не может угадать идентификатор (поскольку рабочий убит при любом неправильном предположении). Кроме того, onmessage
нельзя переопределить code
.
Могу ли я удостовериться, что code
не может "подделать" сообщение остановки, достигнув максимума в стеке, когда код выполняется в среде, которую автор code
не может контролировать (например, на сервере node или в браузере другого пользователя)?
Возможное решение:
Отправьте сообщение "stop" в setTimeout
и скройте scriptId
в закрытии, чтобы он был выполнен сразу после завершения code
.
Этот JSFiddle показывает, что он работает, но, может быть, я упускаю из виду некоторые случаи красных краев?
Это означает, что я меняю код case "run"
на следующее:
postMessage({cmd: "start", args: scriptId}); // signal that script started
setTimeout((function(scriptId) { return function() { postMessage({cmd: "stop", args: scriptId}); };})(scriptId), 0); // signal that script stopped, right after this function returned
scriptId = null;
runScript(code); // runs eval(code) with proper error reporting etc.
Невозможно ли code
читать scriptId
в любой среде исполнения? Меня даже не волнует, может ли он остановить таймер, потому что рабочий будет убит после определенного тайм-аута в любом случае (пока он не может подделать сообщение stop
, которое остановит этот таймер тайм-аута!).