RubyにはCGI等のプログラミングを安全に行うことを助ける為に、セキュリティ機構が備わっています。
Rubyのセキュリティモデルは「オブジェクトの汚染」と「セーフレベル」という仕組みによってなりたっています。
Rubyではオブジェクトは「汚染されている」とみなされることがあります。このしくみは大きく分けて二つの使われ方をします。
ひとつ目は、信用できない入力をもとに作られたオブジェクトを「汚染されている」とみなし、「危険な操作」の引数として使えないようにすることです。悪意あるデータによって、プログラムが意図しない動作をする事を防ぐことを目的としています。
もうひとつは、信用しているオブジェクト(汚染されていないオブジェクト)を信用できないプログラムから守るという使い方です。
オブジェクトの汚染に関連するメソッド
オブジェクトを汚染する
オブジェクトが汚染されている場合に真を返す
オブジェクトの汚染を取り除く
各スレッドは固有の「セーフレベル」を持っています。セーフレベルが高くなるほど、行える操作は制限されます。セーフレベルはスレッドローカル変数 $SAFE で設定します。
$SAFE に関するルール
$SAFE = 0
th = Thread.new{
p $SAFE # => 0
$SAFE = 1
}
th.join
p $SAFE # => 0
$ ruby -e '$SAFE = 1; $SAFE = 0' -e:1: tried to downgrade safe level from 1 to 0 (SecurityError)
原則として、各セキュリティレベルにはそれ以下のセキュリティレベルの制限も適用されます。たとえばレベル1で許されない操作はレベル2でも行えません。
デフォルトのセーフレベルです。
$ ruby -e 'p ARGV[0].tainted?' hoge true
環境変数PATHだけは例外で、値に危険なパスを含む場合のみ汚染されます。
ここでは危険なパスとは誰でも変更/書き込みが可能なパスをいいます。ルートディレクトリから階層が順番にチェックされ、一箇所でも誰でも変更可能な個所があればそのパスは危険とみなされます。
なお、DOSISH(DOSとWindows)、cygwin では権限をチェックしません。
信用しているプログラムで信用できないデータを処理する為のレベルです。 CGI等でユーザからの入力を処理するのに適しています。
$ ruby -e '$SAFE = 1; open(ARGV[0])' hoge -e:1:in `initialize': Insecure operation - initialize (SecurityError) from -e:1
廃止されました。
廃止されました。
廃止されました。
-s -S -e -r -i -I -x
一旦高くした$SAFEレベルを低く変更する事はできませんが、以下のようにスレッドを使うことで、プログラムの一部だけを高いセーフレベルで実行することが可能です。
def safe(level)
result = nil
Thread.start {
$SAFE = level
result = yield
}.join
result
end
lib = "insecure_library".taint # 外部から受け取った文字列(仮)
safe(1) { require lib } # $SAFE が 1 なので例外
require lib # 外側は影響を受けない
@see [ruby-list:37407]