Ruby sandboxing vs. integrating a scripting language
You might consider using the Shikashi gem, which allows you to create sandboxes and define a whitelist of allowed method calls on individual objects.
How to run untrusted Ruby code inside a safe sandbox?
$SAFE is not enough; you need to be at least at the level of Why's freaky sandbox. However, I don't know if that sandbox code is actively maintained or if he/they ever solved the holes such as infinite loops, etc.
Unsafe generally means hostile. If you can relax from hostile to, say, 'naive', and depending upon the requirements of your app, you might get away with sandboxing in Ruby. It's not really a first-class scenario in the language design.
Even with that, though, you probably don't need to go to the machine level of separation. I'd feel pretty safe using a sandbox in a separately spawned process, with your app functioning as a process manager to kill off any that manage to hang/flame. Now, that is a few orders of magnitude more work than your simple block above.
But remember and keep repeating, "SAFE can't deal with hostile".
Ruby\Rails sandboxing
My problem was not so hard to solve without any gems. The idea is that you have whitelist of methods and constants WHITELIST
and this class checks, if all methods and constants are in the whitelist
# gem install 'parser'
require 'parser/current'
class CodeValidator
attr_reader :errors, :source
WHITELIST = {:send => [:puts, :+, :new], :const => [:String]}
class Parser::AST::Node
def value
return children[1] if [:send, :const].include? type
fail NotImplementedError
end
end
def initialize(source)
@errors = []
@source = source
end
def valid?
!insecure_node?(root_node)
end
private
def exclude_node?(node)
blacklisted_node_types.include?(node.type) && !WHITELIST[node.type].include?(node.value)
end
def blacklisted_node_types
WHITELIST.keys
end
def insecure_node?(node)
return !!add_error_for_node(node) if exclude_node?(node)
node.children.each { |child_node| return true if child_node.class == Parser::AST::Node && insecure_node?(child_node) }
false
end
def root_node
@root_node ||= Parser::CurrentRuby.parse source
end
def add_error_for_node(node)
errors << "#{node.type} not allowed: #{node.value}"
end
end
c = CodeValidator.new("s = 'hello ' + String.new('world'); puts s.inspect")
p c.valid? # => false
p c.errors # => ["send not allowed: inspect"]
Ruby: creating a sandboxed eval?
You might want to check the 'taint' method and related stuff. This is a good reference:
http://ruby-doc.com/docs/ProgrammingRuby/html/taint.html
Despite that, I can't advise you enough against storing code and evaluating it, it's a security risk that should be avoided and most times there's a simpler way of solving your problems.
If you need to evaluate complex rules and predicates I'd recommend a rule engine to create a nice DSL. Haven't used one in ruby but this one looks good to me:
http://treetop.rubyforge.org/index.html
Cheers
A scripting engine for Ruby?
There's also Rufus-lua though it's at version 0.1.0...
Related Topics
The Compiler Failed to Generate an Executable File. (Runtimeerror)
Why Can't I Access a Local Variable Inside a Method in Ruby
Detect Key Press (Non-Blocking) W/O Getc/Gets in Ruby
Selenium Scroll Element into (Center Of) View
How to Downgrade from Ruby 1.9.2 to Ruby 1.8.7 to Run Rails 2.0.2
Net::Ssh Sudo Command Hangs After Entering Password
Regex, How to Match Multiple Lines
How Is Each_With_Object Supposed to Work
Ruby - Digest::Digest Is Deprecated; Use Digest
Rails 3 Install Error: "Invalid Value for @Cert_Chain"
Handling Exceptions Raised in a Ruby Thread
How to Get a Particular Line from a File
How to Change Column Type in Heroku
How to Find Out Who Is Connected to Actioncable
Ruby Block to String Instead of Executing
Differencebetween 'Try' and '&.' (Safe Navigation Operator) in Ruby