Pregunta

Currently I can do:

r = ERB.new('Hi there <%= name %>')
r.result(OpenStruct.new(name: 'Joan').instance_eval{ binding })
# Outputs 'Hi there Joan'

But I can also do this (running inside a Rails application with an Admin model):

r = ERB.new('<%= Admin.count %>')
r.result(OpenStruct.new.instance_eval{ binding })
# Outputs '10'

In other words, it has access to all the variables of my app in the context the evaluation is called.

Is there any way to restrict the scope of variables to only what I provide in the binding e.g. only 'name' and nothing else? I'd like to use it in a user-facing templating tool.

I've also tried this (as per another SO question):

class Namespace
  def initialize(hash)
    hash.each do |key, value|
      singleton_class.send(:define_method, key) { value }
    end 
  end

  def get_binding
    binding
  end
end

Same result.

¿Fue útil?

Solución

As an ERB template is compiled down to a plain Ruby method and is executed as such, you can't restrict its access. Through meta-programming, an author of your templates would be able to access everything inside the running Ruby VM and write arbitrary Ruby code.

So even if you would adapt the variable binding passed to the template, this wouldn't restrict a malicious user from accessing all your secrets anyway by embedding Ruby into ERB.

If you really want a safe templating language ready to be exposed to users, you should have a look at Liquid (as Stefan said in a comment) or Mustache, both of which aim to provide a safe, non evaluating template environment.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top