セキュリティモデル

[edit]

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

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

オブジェクトの汚染

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

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

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

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

Object#taint

オブジェクトを汚染する

Object#tainted?

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

Object#untaint

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

セーフレベル

セーフレベルはグローバル変数 $SAFE で設定します。各スレッドで個別のセーフレベルを設定することはできません。セーフレベルが高くなるほど、行える操作は制限されます。

[ruby-list:37415]

$SAFE に関するルール

      $SAFE = 0
      th = Thread.new do
        p $SAFE # => 0
        $SAFE = 1
      ensure
        $SAFE = 0
      end
      th.join
      p $SAFE # => 0
      $ ruby -e '$SAFE = 1; $SAFE = 0'

原則として、各セキュリティレベルにはそれ以下のセキュリティレベルの制限も適用されます。たとえばレベル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 はスレッドローカルからグローバルになり、レベルを低く変更する事もできるようになったため、プログラムの一部だけを高いセーフレベルで実行するには、以下のように ensure でセーフレベルを戻す必要があります。

def safe(level)
  result = nil
  Thread.start do
    $SAFE = level
    result = yield
  ensure
    $SAFE = 0
  end.join
  result
end

lib = "insecure_library".taint # 外部から受け取った文字列(仮)
safe(1) { require lib }        # $SAFE が 1 なので例外
require lib                    # 外側は影響を受けない

拡張ライブラリでの扱い

@see [ruby-list:37407]