セーフレベル
Rubyリファレンスマニュアル - セキュリティモデルより。Rubyでは、セーフレベルによりスレッドが実行可能な操作が制限されます。
- セーフレベル
- スレッドのセキュリティレベルを示す値。0から4まであり、基本的に数が大きくなるほど制限が増える。
- スレッドローカル変数として保持される。スレッドごとの値。
- プログラム開始時のセーフレベルは0。
- スレッド生成時に親スレッドのセーフレベルを引き継ぐ。
- スレッド内で一度数を増やしたら、引き下げることはできない。
例えば、セーフレベル1以上では、汚染されたパスを指定してのファイルへのアクセスが禁止されます。
- 汚染
- オブジェクトが安全かどうかを示す属性値。以下の目的で使用されます。
- 信用できないオブジェクトを入力としてのプログラムの実行を防ぐ
- 信用できないプログラムから、信頼できるオブジェクトを守る
- 例えば、ARGVの文字列はデフォルトで汚染されており、セーフレベル1以上環境であれば、それをパス文字列としてファイルにアクセスすることは禁止されます。
- セーフレベル3以上では、生成されるすべてのオブジェクトが汚染されたりします。
- 「Object#taint」で汚染したり、「Object#untaint」で汚染を解除したりできます。
- オブジェクトが安全かどうかを示す属性値。以下の目的で使用されます。
以下は、0-3の各セーフレベルでファイルにアクセスしてみるサンプルです。
# ブロックを実行し、SecurityErrorとなるのを確認する関数。 def expects_security_error begin yield raise "期待と違う" rescue SecurityError end end path = "./foo" # 汚染されていない文字列 taint_path = "./taint".taint # 汚染された文字列 #--- # セーフレベル0(デフォルト) $SAFE = 0 # 特に制限はなし File.open(path, "w"){|f| f.puts "a" } File.open(taint_path, "w"){|f| f.puts "a" } #--- # セーフレベル1 $SAFE = 1 # 汚染されていないファイルへのアクセスは許可される。 File.open(path, "w"){|f| f.puts "a" } # 汚染された文字列をパスとしてFileを開くとエラー。 # ARGVの値などはデフォルトで汚染されるので、 # ユーザーが入力した安全でないパスへのアクセスを禁止できる。 expects_security_error { File.open(taint_path, "w"){|f| f.puts "a" } } #--- # セーフレベル2 $SAFE = 2 # レベル1と同じく汚染された文字列をパスとしてFileを開くとエラー。 File.open(path, "w"){|f| f.puts "a" } expects_security_error { File.open(taint_path, "w"){|f| f.puts "a" } } # レベル2になると、mkdirやtrapもできなくなる。 expects_security_error { Dir.mkdir("./foo") } expects_security_error { trap(:TERM) { puts "term" } } #--- # セーフレベル3 $SAFE = 3 File.open(path, "w"){|f| f.puts "a" } expects_security_error { File.open(taint_path, "w"){|f| f.puts "a" } } # 生成されるオブジェクトがデフォルトで汚染されるようになる。 expects_security_error { File.open( "./new", "w"){|f| f.puts "a" } } # ちなみに、セーフレベルを下げようとするとエラーになる expects_security_error { $SAFE = 0 }