Выполнение предоставленного пользователем кода ruby ​​на веб-сервере - PullRequest
16 голосов
/ 12 января 2010

Я хотел бы позволить моим пользователям создавать сценарии Ruby, которые выполняют вычисления для некоторых данных, находящихся на веб-сервере, а затем выводят результаты. Скрипты выполняются на сервере. Есть ли способ сделать это безопасно?

Более конкретно, я хотел бы:

  • ограничить ресурсы, которые может использовать скрипт (память и процессор), и ограничить время его работы
  • ограничить, какие основные классы может использовать скрипт (например, String, Fixnum, Float, Math и т. Д.)
  • разрешить скрипту доступ и возврат данных
  • выводить любые ошибки пользователю

Существуют ли какие-либо библиотеки или проекты, которые делают то, что я прошу? Если не в Ruby, может быть, какой-то другой язык?

1 Ответ

17 голосов
/ 12 января 2010

Вы можете использовать «чистый лист» в качестве чистой комнаты и песочницу, в которой можно установить безопасный уровень на 4.

Чистый лист объекта, из которого вы удалили все методы:

class BlankSlate

  instance_methods.each do |name|
    class_eval do
      unless name =~ /^__|^instance_eval$|^binding$|^object_id$/
        undef_method name
      end
    end
  end

end

Чистая комната - это объект, в контексте которого вы оцениваете другой код:

  clean_room = BlankSlate.new

Прочитать команду из ненадежного источника, а затем снять ее. Если не указано иное, Ruby откажется проверить строку в песочнице.

  command = gets
  command.untaint

Теперь запустите строку в песочнице, подняв безопасный уровень до самого высокого уровня. Когда закончится процесс, уровень $ SAFE вернется к нормальному состоянию. Мы выполняем команду в контексте привязки чистой комнаты, чтобы она могла видеть только методы и переменные, которые может видеть чистая комната (помните, однако, что, как и любой объект, чистая комната может видеть что-либо в глобальном пространстве).

  result = proc do
    $SAFE = 4
    clean_room.instance_eval do
      binding
    end.eval(command)
  end.call

распечатать результат:

  p result
...