Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby sandboxing vs. integrating a scripting language

I am currently working on a text-based game engine in Ruby, with the app separated into Ruby code in /lib and YAML data in /data, which is loaded when needed by the game. I want to allow the data files to contain basic scripts, mostly in an event/observer model. However, I also want users to be able to generate and share custom scenarios without having to worry about malicious code embedded in the script.

Addendum: My original plan was to have user-created content separated into two types, "modules" which were data-only (and thus safe) and plugins which added additional functionality (but obviously were not safe). To make an analogy to tabletop gaming, modules would be like published adventure scenarios and content, and plugins would be rulebooks containing additional rules and systems.

Sample script (syntax of course subject to change based on solution):

---
Location:
  observers:
    on_door_open: |
      monster = spawn_monster(:goblin);
      monster.add_item(random_item());
      monster.hostile = true;

From a security standpoint, it would be ideal if scripting was strictly opt-in, probably through an included mixin with a little DSL, e.g.:

class Frog
  include Scriptable

  def jump; ... ; end # this can be called from a script
  allow_scripting :jump

  def ribbit; ... ; end # this cannot be called from a script
end

I've looked at three four options, but I'm not sure which is the best approach to take:

  1. Use Ruby scripting, but in a sandbox of some kind.

    Pros: Very familiar with Ruby, no need for "glue" code or issues integrating objects between languages.

    Cons: Not very familiar with security issues or sandboxing, haven't found any out-of-the-box solutions that seem to fit.

  2. Implement Embed another scripting language, e.g. Lua.

    Pros: Ruby and Lua are C-based, so bindings should be reasonably simple. Lua is a reasonably popular language, so help available if I run into issues later. Secure, since any functionality I don't specifically bind will be unavailable from scripts.

    Cons: Existing Ruby-Lua bindings seem to be one-way, old and poorly maintained, or both. Seems a mite dodgy to embed a scripting language inside another scripting language.

  3. Implement a custom scripting language with Ruby interpreter. I've been experimenting with Treetop, and it shouldn't be too hard to make a simple grammar that would suffice for the scripts.

    Pros: No need to embed another language. Only functionality I've specifically implemented will be available to scripts.

    Cons: Overkill. "Not built here" syndrome. Probably horrible nest of bugs waiting to happen.

  4. Implement the data files entirely in Ruby, using a domain-specific language.

    Pros: Simple and easy.

    Cons: No user-created data is trustable.

I am also open to other suggestions not on that list that I may not have thought of. What is the best solution to safely implement scripts embedded in data files?

Edit 2011年12月23日: Added fourth option with DSL, added "addendum" at top with additional thoughts/context.

like image 902
Rob Smith Avatar asked Dec 23 '11 18:12

Rob Smith


1 Answers

You might consider using the Shikashi gem, which allows you to create sandboxes and define a whitelist of allowed method calls on individual objects.

like image 74
user2398029 Avatar answered Sep 17 '22 14:09

user2398029