Kodougu で必要だったので、Rails アプリ上で Ruby の eval を使用したときの安全性を調査していました。ご存知のとおり、eval 関数は、文字列で渡された Ruby ソースコードを実行するものです。しかし、外部からスクリプトを渡して実行しようとすると、セキュリティの観点から危険な場合があります。以下のような例(外部から渡された script が DB を操作している)です。
script = <<-EOS
# ActiveRecord を操作する
@metaelement = Metaelement.new
@metaelement.name = "execute_eval"
@metaelement.save
EOS
Thread.start {
# $SAFE = 4 <- このコメントアウトを外すと SecurityError 例外発生
eval(script)
}.join
デフォルトでは上記のコードは動作します。安全ではない eval です。しかし、$SAFE = 4 にして上記のコードを実行すると、SecurityError 例外が発生します。Ruby のセキュリティモデル Level 4 には、「汚染されていないオブジェクトの状態の変更」を禁止するルールがあるので、これに引っかかったようです。Level 4 では以下のようなコードでも SecurityError 例外が発生します。
script = <<-EOS
@metaelements = Metaelement.find(:all)
EOS
Thread.start {
$SAFE = 4
eval(script)
}.join
では、Rails でも Level 4 で eval すれば安全・・・というと、ちょっと自信がありません。たとえば以下のようなコードは動作してしまいます。
script = <<-EOS
Metaelement.connection # DB のコネクションを取得。
EOS
Thread.start {
$SAFE = 4
eval(script)
}.join
上記のようなコードの動作を許可すると、DB のユーザ、パスワードとかを取れてしまいます。見られたくない情報です。eval の用途によっては非常に危険です。危険な例としては、ページ上で eval で評価した結果を表示する場合などが挙げられます。Rails の全メソッドに rb_secure(1) とかを仕込めばいいのでしょうかね。(^^; (ありとあらゆる面から論外でしょうけど。)
Ruby on Rails でサンドボックスというのはさすがに無理ですかね~。。。