Как ограничить доступ узла repl к внутренним модулям узла?

В предыдущем вопросе я выяснил, как исключить нежелательные глобальные переменные из контекста repl. Однако я выяснил, что repl автоматически имеет доступ ко ВСЕМ внутренним модулям узла без использования require. Я понятия не имею, как отключить это. Я даже пытался переопределить переменные модуля в самом repl, и это не сработало.

› fs = "тест";
› fs

Он по-прежнему отображает исходное значение fs. Это очень прискорбно, потому что я пытаюсь выставить публичный ответ, но он дает им доступ ко всему серверу.

Любые идеи?


person Chev    schedule 16.10.2013    source источник


Ответы (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();
person Laurent Perrin    schedule 16.10.2013
comment
Я ценю это. Я уже запускаю экземпляры repl в отдельных дочерних процессах, где они могут взорваться без какого-либо серьезного воздействия на сервер. Мне просто нужно выяснить, как избавиться от основных модулей. Мне действительно не нравится, что их нельзя настроить. Я думаю, что я, вероятно, просто разветвлю модуль repl, сделаю эти вещи настраиваемыми и опубликую модифицированный модуль. - person Chev; 16.10.2013
comment
Да, странно, что нельзя отказаться. Даже если вы измените контекст, встроенные модули будут добавлены. Разработчики, вероятно, решили, что repl небезопасен по своей конструкции, и хуже от этого не станет. - person Laurent Perrin; 16.10.2013
comment
На самом деле, я думаю, вы можете отказаться. Вы связали меня с кодом модуля. Я думаю, все, что мне нужно сделать, это переопределить repl._builtinLibs, прежде чем я вызову repl.start(). Я собираюсь попробовать это сейчас. - person Chev; 16.10.2013
comment
вот так. Я этого не понимал. Однако есть и другие встроенные функции, которые могут вам помешать, например .save: github.com/joyent/node/blob/master/lib/repl.js#L856 - person Laurent Perrin; 16.10.2013
comment
Хороший звонок. Я должен проверить их тоже, но я думаю, что мы, наконец, добрались до этого. Кстати сработало. Просто сделайте repl._builtinLibs = []; перед запуском repl. Я собираюсь отредактировать и принять ваш ответ, если все в порядке. - person Chev; 16.10.2013
comment
приятно :) это может оказаться полезным когда-нибудь. - person Laurent Perrin; 16.10.2013
comment
Я также выяснил, как удалить нежелательные команды repl. Я собираюсь добавить это к вашему ответу. - person Chev; 16.10.2013