Ruby 2.1.0 リファレンスマニュアル > セキュリティモデル

セキュリティモデル

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

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

オブジェクトの汚染

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

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

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

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

Object#taint

オブジェクトを汚染する

Object#tainted?

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

Object#untaint

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

セーフレベル

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

[ruby-list:37415]

$SAFE に関するルール

      $SAFE = 1
      th = Thread.new{
        p $SAFE #=> 1
        $SAFE = 3
      }
      th.join
      p $SAFE #=> 1
      $ 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

汚染されるオブジェクト

禁止される操作

レベル1の制限に加え、以下の操作が禁止されます。

レベル 3

生成される全てのオブジェクトが汚染されます。

汚染されるオブジェクト

禁止される操作

レベル2の制限に加え、以下の操作が禁止されます。

レベル 4

廃止されました。

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

      * 環境変数 RUBYLIB を $: に加えない
      * 環境変数 RUBYOPT を処理しない
      * 以下のスイッチを使用できない
        -s -S -e -r -i -I -x
        (スクリプトがsetgid, setuidされている時も同様)
      * 標準入力からのプログラム読み込みを行わない
        (スクリプトがsetgid, setuidされている時も同様)

使用例

一旦高くした$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]