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, eg:

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:

  • 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.

  • Implement Embed another scripting language, eg 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.

  • 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.

  • 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.


    您可以考虑使用Shikashi gem,它允许您创建沙箱并为单个对象定义允许的方法调用的白名单。


    Consider using jRuby instead of Ruby. Java was originally implemented to support mobile code (back in the set-top days) and has a well-tested security model/implementation that could, I suspect, wrap enough of jRuby to keep user scripts/classes from creating havoc with the rest of the game system. jRuby supports embedding, as well, which may help separate the game core from the user applications, although I do not know how robust it is at this time.

    And, of course, jRuby is Ruby!

    链接地址: http://www.djcxy.com/p/95456.html

    上一篇: 将JavaScript嵌入到应用程序中(如Lua)

    下一篇: Ruby sandboxing与整合脚本语言