30.1. rexec —制限された実行フレームワーク—Pythonドキュメント

提供:Dev Guides
< PythonPython/docs/2.7/library/rexec
移動先:案内検索

30.1。 rexec —制限された実行フレームワーク

バージョン2.6以降非推奨: rexec モジュールはPython3で削除されました。


バージョン2.3で変更:モジュールを無効にしました。


警告

モジュールを使用する古いコードを読むのに役立つように、ドキュメントはそのまま残されています。


このモジュールには、r_eval()r_execfile()r_exec()、およびr_import()メソッドをサポートする RExec クラスが含まれています。標準のPython関数 eval()execfile()、および exec および import ステートメント。 この制限された環境で実行されたコードは、安全と見なされるモジュールと機能にのみアクセスできます。 RExec をサブクラス化して、必要に応じて機能を追加または削除できます。

警告

rexec モジュールは、以下で説明するように実行するように設計されていますが、注意深く記述されたコードによって悪用される可能性のある既知の脆弱性がいくつかあります。 したがって、「本番環境に対応した」セキュリティが必要な状況では、これに依存しないでください。 このような状況では、サブプロセスを介した実行、または処理するコードとデータの両方の非常に注意深い「クレンジング」が必要になる場合があります。 または、既知の rexec の脆弱性にパッチを適用することを歓迎します。


ノート

RExec クラスは、コードがディスクファイルの読み取りや書き込み、TCP / IPソケットの使用などの安全でない操作を実行するのを防ぐことができます。 ただし、非常に大量のメモリまたはプロセッサ時間を使用するコードからは保護されません。


class rexec.RExec([hooks[, verbose]])

RExec クラスのインスタンスを返します。

hooks は、RHooksクラスまたはそのサブクラスのインスタンスです。 省略またはNoneの場合、デフォルトのRHooksクラスがインスタンス化されます。 rexec モジュールがモジュール(組み込みモジュールであっても)を検索したり、モジュールのコードを読み取ったりするときは常に、実際にはファイルシステム自体に送信されません。 むしろ、コンストラクターに渡された、またはコンストラクターによって作成されたRHooksインスタンスのメソッドを呼び出します。 (実際には、 RExec オブジェクトはこれらの呼び出しを行いません。これらの呼び出しは RExec オブジェクトの一部であるモジュールローダーオブジェクトによって行われます。 これにより、別のレベルの柔軟性が可能になり、制限された環境内で import のメカニズムを変更するときに役立ちます。)

代替のRHooksオブジェクトを提供することにより、モジュールをインポートするために行われるファイルシステムアクセスを制御できます。これらのアクセスが行われる順序を制御する実際のアルゴリズムを変更する必要はありません。 たとえば、ILUなどのRPCメカニズムを介して、すべてのファイルシステム要求を別の場所のファイルサーバーに渡すRHooksオブジェクトに置き換えることができます。 Grailのアプレットローダーはこれを使用して、ディレクトリのURLからのアプレットのインポートをサポートします。

verbose がtrueの場合、追加のデバッグ出力が標準出力に送信される場合があります。

制限された環境で実行されているコードは、引き続き sys.exit()関数を呼び出すことができることに注意することが重要です。 制限されたコードがインタープリターを終了することを禁止するには、SystemExit例外をキャッチする try / exception ステートメントで制限されたコードを実行する呼び出しを常に保護します。 制限された環境から sys.exit()関数を削除するだけでは不十分です。制限されたコードは、引き続きraise SystemExitを使用できます。 SystemExitを削除することは合理的なオプションではありません。 一部のライブラリコードはこれを利用しており、利用できない場合は機能しなくなります。

も参照してください

グレイルホームページ
Grailは、完全にPythonで記述されたWebブラウザです。 rexec モジュールをPythonアプレットをサポートするための基盤として使用し、このモジュールの使用例として使用できます。


30.1.1。 RExecオブジェクト

RExec インスタンスは、次のメソッドをサポートします。

RExec.r_eval(code)
code は、Python式を含む文字列、または制限された環境の __ main __ モジュールで評価されるコンパイル済みコードオブジェクトのいずれかである必要があります。 式またはコードオブジェクトの値が返されます。
RExec.r_exec(code)
code は、Pythonコードの1行以上を含む文字列、または制限された環境の __ main __ モジュールで実行されるコンパイル済みコードオブジェクトのいずれかである必要があります。
RExec.r_execfile(filename)
制限された環境の __ main __ モジュールのファイル filename に含まれているPythonコードを実行します。

名前がs_で始まるメソッドは、r_で始まる関数に似ていますが、コードは標準I / Oストリームの制限付きバージョンsys.stdin、[ X194X] 、およびsys.stdout

RExec.s_eval(code)
code は、制限された環境で評価されるPython式を含む文字列である必要があります。
RExec.s_exec(code)
code は、制限された環境で実行される1行以上のPythonコードを含む文字列である必要があります。
RExec.s_execfile(code)
制限された環境でファイル filename に含まれているPythonコードを実行します。

RExec オブジェクトは、制限された環境で実行されるコードによって暗黙的に呼び出されるさまざまなメソッドもサポートする必要があります。 サブクラスでこれらのメソッドをオーバーライドすることは、制限された環境によって適用されるポリシーを変更するために使用されます。

RExec.r_import(modulename[, globals[, locals[, fromlist]]])
モジュール modulename をインポートし、モジュールが安全でないと見なされた場合はImportError例外を発生させます。
RExec.r_open(filename[, mode[, bufsize]])
制限された環境で open()が呼び出されたときに呼び出されるメソッド。 引数は open()の引数と同じであり、ファイルオブジェクト(またはファイルオブジェクトと互換性のあるクラスインスタンス)を返す必要があります。 RExec のデフォルトの動作では、読み取り用に任意のファイルを開くことができますが、ファイルを書き込もうとする試みは禁止されています。 制限の少ない r_open()の実装については、以下の例を参照してください。
RExec.r_reload(module)
モジュールオブジェクト module をリロードし、再解析して再初期化します。
RExec.r_unload(module)
モジュールオブジェクト module をアンロードします(制限された環境のsys.modulesディクショナリから削除します)。

また、制限された標準I / Oストリームにアクセスできる同等のもの:

RExec.s_import(modulename[, globals[, locals[, fromlist]]])
モジュール modulename をインポートし、モジュールが安全でないと見なされた場合はImportError例外を発生させます。
RExec.s_reload(module)
モジュールオブジェクト module をリロードし、再解析して再初期化します。
RExec.s_unload(module)
モジュールオブジェクトモジュールをアンロードします。


30.1.2。 制限された環境の定義

RExec クラスには、__init__()メソッドで使用される次のクラス属性があります。 既存のインスタンスでそれらを変更しても効果はありません。 代わりに、 RExec のサブクラスを作成し、クラス定義でそれらに新しい値を割り当てます。 新しいクラスのインスタンスは、それらの新しい値を使用します。 これらの属性はすべて文字列のタプルです。

RExec.nok_builtin_names
制限された環境で実行されているプログラムでは使用できない組み込み関数の名前が含まれています。 RExec の値は('open', 'reload', '__import__')です。 (これは例外を与えます。なぜなら、組み込み関数の大部分は無害だからです。 この変数をオーバーライドしたいサブクラスは、おそらく基本クラスの値で始まり、追加の禁止関数を連結する必要があります。新しい危険な組み込み関数がPythonに追加されると、それらもこのモジュールに追加されます。)
RExec.ok_builtin_modules
安全にインポートできる組み込みモジュールの名前が含まれています。 RExec の値は('audioop', 'array', 'binascii', 'cmath', 'errno', 'imageop', 'marshal', 'math', 'md5', 'operator', 'parser', 'regex', 'select', 'sha', '_sre', 'strop', 'struct', 'time')です。 この変数のオーバーライドに関する同様の注意事項が適用されます—基本クラスの値を開始点として使用します。
RExec.ok_path
制限された環境で import が実行されたときに検索されるディレクトリが含まれています。 RExec の値は、無制限コードのsys.path(モジュールのロード時)と同じです。
RExec.ok_posix_names
制限された環境で実行されているプログラムで使用できる os モジュールの関数の名前が含まれています。 RExec の値は('error', 'fstat', 'listdir', 'lstat', 'readlink', 'stat', 'times', 'uname', 'getpid', 'getppid', 'getcwd', 'getuid', 'getgid', 'geteuid', 'getegid')です。
RExec.ok_sys_names
sys モジュールの関数と変数の名前が含まれています。これらは、制限された環境で実行されているプログラムで使用できます。 RExec の値は('ps1', 'ps2', 'copyright', 'version', 'platform', 'exit', 'maxint')です。
RExec.ok_file_types
モジュールのロードが許可されているファイルタイプが含まれています。 各ファイルタイプは、 imp モジュールで定義されている整数定数です。 意味のある値は、PY_SOURCEPY_COMPILED、およびC_EXTENSIONです。 RExec の値は(C_EXTENSION, PY_SOURCE)です。 サブクラスにPY_COMPILEDを追加することはお勧めしません。 攻撃者は、偽造されたバイトコンパイル済みファイル(.pyc)をファイルシステムの任意の場所に置くことによって、制限された実行モードを終了する可能性があります。たとえば、/tmpに書き込んだり、/incomingディレクトリ。


30.1.3。 例

標準の RExec クラスよりも少し緩和されたポリシーが必要だとしましょう。 たとえば、/tmp内のファイルの書き込みを許可する場合は、 RExec クラスをサブクラス化できます。

class TmpWriterRExec(rexec.RExec):
    def r_open(self, file, mode='r', buf=-1):
        if mode in ('r', 'rb'):
            pass
        elif mode in ('w', 'wb', 'a', 'ab'):
            # check filename: must begin with /tmp/
            if file[:5]!='/tmp/':
                raise IOError("can't write outside /tmp")
            elif (string.find(file, '/../') >= 0 or
                 file[:3] == '../' or file[-3:] == '/..'):
                raise IOError("'..' in filename forbidden")
        else: raise IOError("Illegal open() mode")
        return open(file, mode, buf)

上記のコードでは、完全に有効なファイル名が禁止される場合があることに注意してください。 たとえば、制限された環境のコードは、/tmp/foo/../barというファイルを開くことができません。 これを修正するには、r_open()メソッドでファイル名を/tmp/barに簡略化する必要があります。これには、ファイル名を分割してさまざまな操作を実行する必要があります。 セキュリティが危機に瀕している場合は、より複雑で微妙なセキュリティホールを抱えている可能性のあるより一般的なコードではなく、時には過度に制限的な単純なコードを作成する方が望ましい場合があります。