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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With