Nicolas
Nicolas

Reputation: 2367

Executing arbitrary functions in Ruby without the security problems of eval

I have a Ruby on Rails app and I need to add some arbitrary 'functions' to the database. These functions need to receive predefined parameters, perform arbitrary logic and arithmetic, and return a number or a string.

My first idea was to add the code to the DB and use eval(code), but I soon realised the security issue with this. I could not find a way of a really sandboxed eval.

I also thought about using a JavaScript interpreter, for example, to have the code in JS and run it it's own context, but it still seems a bit too much and not secure enough.

Is there a way to execute simple arbitrary logic and arithmetic from a string over some variables and return a value?

Upvotes: 0

Views: 171

Answers (2)

Thiago Lewin
Thiago Lewin

Reputation: 2828

Run arbitrary code it is a unsafe practice and very difficult to ensure that you control all variables and different scenarios.

You can try to patch all Ruby classes/ modules that can run any malicious code, like IO, Kernel, etc, but in the end you will have many classes patched, very difficult to maintain and will not have sure if it will work safely.

The best solution that I can figure out is to create your own programming language where you can ensure all functions and operations that the user will have access.

Nowadays there are many solutions, paper and examples that makes this task not so difficult, for example Ragel http://www.complang.org/ragel/ that compiles to Ruby.

You can start with few operations (if, arithmetic, logic, etc) and improve it incrementally. In the end, you will have a robust solution that can easily evolve to fit on users needs.

Upvotes: 1

Alex Wayne
Alex Wayne

Reputation: 187004

How sophisticated does this code need to be? Or conversely, how arbitrary does it need to be? Hopefully, you don't need to store code.

Instead, keep code in your code, and data in your data. Then simply reference names of procedures. For example:

class User
  def contact
    case self.prefers_contact_method
    when :email
      Email.send_to self.email
    when :sms
      SMS.send_to self.mobile_number
    when :call
      Phone.place_call self.home_number
    end
  end
end

Putting executable code in your database is not a good idea. Avoid it at all costs. And if you really need to do it, then maybe you should rethink your approach.


And if you really really need to do this, you need a sandbox. Some environment where you can control what arbitrary code has access to so that there is no dangerous code that is possible to be executed. See: Ruby sandboxing vs. integrating a scripting language

But even so, it's a scary thing to open yourself up to. Tread very carefully with this, and think thoroughly through the security implications.

Upvotes: 0

Related Questions