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 あかさた
私は Ruby の module のテストは以下のように行っています。

[code: def test_hoge

@dummy_object = Object.new
@dummy_object.extend(HogeModule)
assert ...hogehoge...
end]

他にも以下のような方法も考えられます。クラスを生成してからモジュールを拡張する方法です。

[code: def test_hoge

@new_class = Class.new
@dummy_object = @new_class.allocate
@dummy_object.extend(HogeModule)
assert ...hogehoge...
end]

コードとしては以下がわかりやすいかも。明示的にテスト用のクラスを作成する場合です。

[code: class Dummy

include HogeModule
end

def test_hoge
@dummy_object = Dummy.new
assert ...hogehoge...
end]

Ruby の module は Java や C# には無い概念なのでどういうテストをしたらいいのか悩みますね。

Posted by あかさた
Ruby プログラムを .NET Framework 2.0 上で動作する DLL/EXE に変換する Ruby.NET Compiler ソフトウェアがあります。気になったのでちょっと調べてみました。

本記事は、Gardens Point Ruby.NET Compiler Beta Release(February 2007)に対応しています。

■ 知りたいこと
・ 既存の Ruby ライブラリが使えるか
・ 既存の .NET ライブラリが使えるか
・ 既存のアプリケーションに組み込めるか
・ ライセンスは使いやすいか
・ 安定度はどれくらいか
・ 開発は活発か

■ 調査結果
・ 既存の Ruby ライブラリが使えるか
実装していないようです。実装予定があるかどうかも不明です。

・ 既存の .NET ライブラリが使えるか
次のリリースで対応する(したい)ようです。

・ 既存のアプリに組み込めるか
ちゃんとコードは追っていませんが、高い頻度で動的に書き換えるのはパフォーマンス的にネックになりそう(※)ですが、それほどでなければ大丈夫そうです。

※ コンパイラであるためです。ただ、IronPython もコンパイル可能でわりと動的に書き換えてもそれほどパフォーマンスでネックにはならないので、このツールもこなれてくれば大丈夫ではないかなと楽観しています。IronPython を組み込む際は、ランタイムのロード時間のほうが問題になりました(IronPython というよりは .NET 系全般の問題)。ゲームとかリアルタイム性が必要なアプリの場合は、ランタイムを呼び出すタイミングをコントロールする必要があります。
(IronPython では、WinXP/P4 2.8GHz/1GB の PC で秒間 50 フレームで HelloWorld をパースさせたら CPU 使用率が 100% になった <- あたりまえ^^;)

コンパイラなので、既存のアプリに組み込むことは想定に入っていないのか、プログラミングインタフェースは、まだ整理されていないように見えました。IronPython のように 1 行で組み込むというわけにはいかないという印象を受けました。

・ ライセンスは使いやすいか
BSD ライセンスに近い印象を受けました。このページの Licensing という箇所を参照してください。以下の内容が書かれています。というわけで結構使いやすいのではないかと思っています。

続きを読む

Posted by あかさた
そろそろ Ruby の勉強を本格的にしたいと感じたので、まずは動的にクラスを定義する方法を調べてみました。以下のコードでは、動的にクラスを定義して、アクセッサ(my_name)を追加しています。

# Class の定義
my_new_class = Class.new
my_new_class.class_eval("attr_accessor :my_name")

# Instance の生成
my_new_object = my_new_class.allocate

# 生成した Instance を使用する
my_new_object.my_name = "akasata"
printf "My name is %s!\n", my_new_object.my_name

ここまでは楽勝です。さすがは Ruby。(LL では大抵楽勝だと思いますが。)

Posted by あかさた
Kodougu の開発中に気になったのですが、ブラウザをリロードしても JavaScript の更新が反映されないことがあるようです。キャッシュが効いているのでしょう。

Rails では、javascript_include_tag メソッドを使うと、以下のように JavaScript のファイル名の後ろに数字(たぶん時間)を追加して展開してくれます。これだと、アクセスするたびに URL が変更されるため、ブラウザのキャッシュの影響を受けません。
[code: ]

SVG では JavaScript のインクルードは xlink を使うため、Rails のヘルパーメソッドを使うことはできません。そこで、以下のように書いてみました。
[code: