Как ограничить доступ узла repl к внутренним модулям узла?
В предыдущем вопросе я выяснил, как убрать нежелательные глобальные переменные из контекста repl. Однако я выяснил, что repl автоматически имеет доступ ко ВСЕМ модулям внутренних узлов без использования require
, Я понятия не имею, как отключить это. Я даже попытался переопределить переменные модуля в самом repl, и это не работает.
> fs = "test";
> фс
Это все еще отображает fs
первоначальная стоимость Это очень прискорбно, потому что я пытаюсь открыть публичный репл, но он дает им доступ ко всему серверу.
Есть идеи?
1 ответ
Как вы сказали, REPL имеет доступ к основным модулям.
(однако после проверки я могу переопределить их с помощью узла 0.10.20, поэтому должно быть решение)
> fs
> { Stats: [Function], …
> fs = 'hello';
> fs
'hello'
Лучше было бы просто переопределить repl._builtinLibs
перед созданием экземпляра repl.
var repl = require('repl');
repl._builtinLibs = [];
repl.start('> ');
Кроме того, довольно просто выполнять команды repl из белого списка, если вы не хотите показывать такие команды, как .save
или же .load
,
var allowedReplCmds = ['.break', '.clear', '.help'];
var newRepl = repl.start('> ');
for (var key in newRepl.commands)
if (!allowedReplCmds.contains(key))
delete replInstance.commands[key];
Примечание. Массивы обычно не имеют contains
метод, поэтому я добавил один.
Array.prototype.contains = function(v) {
for(var i = 0; i < this.length; i++) {
if(this[i] === v) return true;
}
return false;
};
Если вы хотите удалить переменные из глобальной области действия экземпляра repl, посмотрите этот вопрос.
Пожалуйста, обратите внимание, что очень небезопасно выставлять REPL для общественности.
Вы можете легко разбить весь сервер
> setTimeout(function () { throw 'bye bye!'; }, 0);
Ошибки, которые происходят в асинхронных обратных вызовах, не перехватываются REPL и сбивают экземпляр node.js.
Вы можете заблокировать сервер
> while(true) {};
Лучше всего было бы написать собственный REPL в отдельном процессе с помощью child_process, readline и vm. Вот отправная точка:
Хозяин:
// master.js
var fork = require('child_process').fork;
// functions exposed to the repl
var replApi = {
hello: function () {
return 'world!';
},
unknown: function () {
return 'unknown';
}
};
function forkRepl() {
var repl = fork('./child_repl');
repl.on('message', function (command) {
var fun = replApi[command] || replApi.unknown;
repl.send(fun());
});
// restart the repl if it dies
repl.on('exit', forkRepl);
}
forkRepl();
и отдельный процесс для repl:
// child_repl.js
var readline = require('readline'),
vm = require('vm');
var context = vm.createContext({
hello: function () {
process.send('hello');
}
});
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.on('line', function (line) {
vm.runInContext(line, context, 'repl.vm');
});
process.on('message', function (message) {
console.log('master:', message);
});
rl.prompt();