セキュリティモデル

RubyにはCGI等のプログラミングを安全に行うことを助ける為に、セキュリティ機構が備わっています。

Rubyのセキュリティモデルは「オブジェクトの汚染」と「セーフレベル」という仕組みによってなりたっています。

オブジェクトの汚染

Rubyではオブジェクトは「汚染されている」とみなされることがあります。このしくみは大きく分けて二つの使われ方をします。

ひとつ目は、信用できない入力をもとに作られたオブジェクトを「汚染されている」とみなし、「危険な操作」の引数として使えないようにすることです。悪意あるデータによって、プログラムが意図しない動作をする事を防ぐことを目的としています。

もうひとつは、信用しているオブジェクト(汚染されていないオブジェクト)を信用できないプログラムから守るという使い方です。

オブジェクトの汚染に関連するメソッド

Object#taint

オブジェクトを汚染する

Object#tainted?

オブジェクトが汚染されている場合に真を返す

Object#untaint

オブジェクトの汚染を取り除く

セーフレベル

各スレッドは固有の「セーフレベル」を持っています。セーフレベルが高くなるほど、行える操作は制限されます。セーフレベルはスレッドローカル変数 $SAFE で設定します。

[ruby-list:37415]

$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でも行えません。

レベル 0

デフォルトのセーフレベルです。

汚染されるオブジェクト

$ ruby -e 'p ARGV[0].tainted?' hoge
true

環境変数PATHだけは例外で、値に危険なパスを含む場合のみ汚染されます。

ここでは危険なパスとは誰でも変更/書き込みが可能なパスをいいます。ルートディレクトリから階層が順番にチェックされ、一箇所でも誰でも変更可能な個所があればそのパスは危険とみなされます。

なお、DOSISH(DOSとWindows)、cygwin では権限をチェックしません。

禁止される操作

レベル 1

信用しているプログラムで信用できないデータを処理する為のレベルです。 CGI等でユーザからの入力を処理するのに適しています。

汚染されるオブジェクト

禁止される操作

          $ ruby -e '$SAFE = 1; open(ARGV[0])' hoge
          -e:1:in `initialize': Insecure operation - initialize (SecurityError)
                  from -e:1

レベル 2

廃止されました。

レベル 3

廃止されました。

レベル 4

廃止されました。

セーフレベルに関するその他の詳細

          -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]