For various reasons I need to be able to be able to accept some script input from the client.
The basic requirement is to be able to accept some Ruby code from the client in order to allow customisation of the HTML output from an RSS feed.
This is obviously a rather dangerous thing. I essentially need to allow arbitrary Ruby to be executed with an eval
However, in Ruby, we can run code in SAFE mode.
At Level 4:
Ruby effectively partitions the running program in two. Nontainted objects may not be modified. Typically, this will be used to create a sandbox: the program sets up an environment using a lower
$SAFElevel, then resets$SAFEto 4 to prevent subsequent changes to that environment
The core of my approach is to create a new Thread, set the SAVE level to 4 and call a method.
feed = FeedNormalizer::FeedNormalizer.parse(open(self.url))
thread = Thread.start {
$SAFE = 4
html = safe_method(feed, script)}
}
thread.join #wait for the thread to finish
The safe_method itself does a sanity check on the safe level. The method takes a feed object and a script – the script is processed using eval and because the feed object is in the context, the script has access to it. However, the safe level prevents any malicious code from attempting to use Ruby magic and meta-programming to gain access to variables outside the thread or any globals
def safe_method(feed,script)
if ( $SAFE < 4 )
raise “SecurityException: attempting to execute UNSAFE script”
endhtml = “”
eval(script)
return html
end
The user can then pass in code that looks like:
html << “<h2>#{feed.title}</h2>”
html << “<ul>”
feed.entries.each do |entry|
html << “<li><a href=\”#{entry.urls.first}\”>#{entry.title}</a></li>”
end
html << “</ul>”
And the feed is processed without (too much) risk.
Bad things done well: accepting dangerous input with Rails…
[...]Sometimes you have to do things that are dangerous. In my case I had to accept script input from the browser and work out a way of executing it without having my system totally hacked. Discover how to run Ruby code in a Sandbox![...]…
LiquidMarkup looks pretty comprehensive, I might have a look at it.