Как ограничить доступ узла 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();
Другие вопросы по тегам