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 でサンドボックスというのはさすがに無理ですかね~。。。


Posted by あかさた
最近のエントリ
最近の読書メモ