第 42章セーフモード

PHP のセーフモードは、共有サーバでのセキュリティの問題を解決するための試みです。 この問題を PHP のレベルで解決しようとするのはアーキテクチャ上正しくありません。 しかし、Web サーバや OS レベルでの代替策はあまり現実的ではないため、 多くのユーザ、特に ISP ではセーフモードが現在使用されています。

警告

セーフモードは、PHP 6.0.0 で削除されます。

セキュリティとセーフモード

表 42-1. セキュリティとセーフモード設定ディレクティブ

名前 デフォルト 変更の可否 変更履歴
safe_mode "0" PHP_INI_SYSTEM  
safe_mode_gid "0" PHP_INI_SYSTEM PHP 4.1.0 から利用可能
safe_mode_include_dir NULL PHP_INI_SYSTEM PHP 4.1.0 から利用可能
safe_mode_exec_dir "" PHP_INI_SYSTEM  
safe_mode_allowed_env_vars "PHP_" PHP_INI_SYSTEM  
safe_mode_protected_env_vars "LD_LIBRARY_PATH" PHP_INI_SYSTEM  
open_basedir NULL PHP_INI_SYSTEM  
disable_functions "" php.ini only PHP 4.0.1 から利用可能
disable_classes "" php.ini only PHP 4.3.2 から利用可能
PHP_INI_*の定義と詳細については、 ini_set() を参照してください。

以下に設定ディレクティブに関する 簡単な説明を示します。

セーフモードの設定ディレクティブの簡単な説明を以下に示します。

safe_mode boolean

セーフモードを有効にするか否か。

safe_mode_gid boolean

デフォルトでは、セーフモードはオープンしようとするファイルの UIDの比較チェックを行います。GIDの比較にすることでこのチェックを 緩やかなものにしたい場合、safe_mode_gidをオンにしてください。 ファイルにアクセスする際に UID ( FALSE )を使用するか GID ( TRUE )を使用するか制御できます。

safe_mode_include_dir string

このディレクトリ(そのサブディレクトリも含む)の配下のファイルが インクルードされる場合、 UID / GID のチェックはバイパスされます。(ディレクトリは include_path の配下であるか あるいはフルパスで記述される必要があります)

PHP 4.2.0以降、このディレクティブは include_path と同様に コロン(Windowsではセミコロン)で分けた形式で複数のパスを書くことができます。

ここで指定される制限は実はプレフィックスでありディレクトリ名ではありません。 つまり、"safe_mode_include_dir = /dir/incl" と書くと "/dir/include" と "/dir/incls" の両方へのアクセスが許可されます(もし ディレクトリが存在すれば)。指定したディレクトリのみを許可したい 場合には、最後にスラッシュを追加してください。 例:"safe_mode_include_dir = /dir/incl/"

PHP 4.2.3 と PHP 4.3.3 以降では、ディレクティブの値が空の場合、 異なる UID / GID を持つファイルを インクルードすることはできません。 以前のバージョンでは、全てのファイルをインクルード可能でした。

safe_mode_exec_dir string

PHPがセーフモードで動作する場合、 system() や その他の プログラム実行関数 を、 このディレクトリ以外で起動することは拒否されます。 Windowsを含む全ての環境において ディレクトリのセパレータとして / を使用する必要があります。

safe_mode_allowed_env_vars string

ある種の環境変数の設定はセキュリティ上の潜在的な欠陥となりえます。 このディレクティブにはプレフィックスをカンマで区切って書くことができます。 セーフモードでは、ここに書かれたプレフィックスで始まる環境変数だけを ユーザーが変更できるようになります。デフォルトでは、ユーザーは PHP_で始まる名前の環境変数(e.g. PHP_FOO=BAR)だけをセットすることができます。

注意: このディレクティブが空の場合、PHPは全ての環境変数について ユーザーが変更することを許可してしまいます。

safe_mode_protected_env_vars string

putenv() を使ってエンドユーザーが変更するのを 防ぎたい環境変数をカンマ区切りで記述します。ここで設定された環境変数は もしもsafe_mode_allowed_env_varsでは許可されているものであっても 保護されます。

open_basedir string

PHPによってオープンされうるファイルを特定のディレクトリツリー に制限します。このディレクティブはセーフモードのオン/オフに 関わらず 適用されます。

例えばfopenやfzopenを使ってスクリプトがファイルをオープンしようと するとそのファイルの位置がチェックされます。指定された ディレクトリツリーの範囲外にあった場合、PHPはオープンを拒否します。 全てのシンボリックリンクは解決されますので、シンボリックリンクを使って この制限を回避することは不可能です。

. は特別な値で、 スクリプトが格納されているワーキングディレクトリをベースディレクトリとして 使用することを意味します。 これは、しかし、スクリプトのワーキングディレクトリが chdir() により容易に変更されるために やや危険です。

httpd.conf の中で、open_basedir はオフにすることができます。 (例: 仮想サーバの場合) 他の設定ディレクティブと 同様に "php_admin_value open_basedir none"とします。

Windows上では、ディレクトリをセミコロンで区切ってください。 その他全てのシステムでは、ディレクトリをコロンで区切ってください。 Apacheモジュールでは、親ディレクトリからopen_basedirへのパス は自動的に継承されます。

ここで指定される制限は実はプレフィックスでありディレクトリ名ではありません。 つまり、"open_basedir = /dir/incl" と書くと "/dir/include" と "/dir/incls" の両方へのアクセスが許可されます(もし ディレクトリが存在すれば)。指定したディレクトリのみを許可したい 場合には、最後にスラッシュを追加してください。 例:"open_basedir = /dir/incl/"

注意: 複数のディレクトリへの対応は3.0.7で追加されました。

デフォルトでは全てのファイルのオープンが許可されます。

disable_functions string

セキュリティ を考慮したい場合に このティレクティブを使って、特定の関数を無効にすることができます。 関数名をカンマ区切りで表記してください。disable_functionsは セーフモード の影響を受けません。

このディレクティブは php.ini 上でセットされなければなりません。 例えば、 httpd.conf 等でセットすることはできません。

disable_classes string

セキュリティ を考慮したい場合に このティレクティブを使って特定のクラスを無効にすることができます。 クラス名をカンマ区切りで表記してください。disable_classsは セーフモード の影響を受けません。

このディレクティブは php.ini 上でセットされなければなりません。 例えば、 httpd.conf 等でセットすることはできません。

Availability note: このディレクティブはPHP4.3.2で追加されました。

register_globals , display_errors , log_errors も参照してください。

セーフモード がonの場合、PHPは、 現在のスクリプトの所有者がファイル関数により処理されているファイルまたはディレクトリ の所有者に一致するかどうかを調べます。例えば、

-rw-rw-r--    1 rasmus   rasmus       33 Jul  1 19:20 script.php -rw-r--r--    1 root     root       1116 May 26 18:01 /etc/passwd
以下のscript.php を実行すると、
<?php
readfile
( '/etc/passwd' );
?>
セーフモードが有効な場合、以下のようなエラーが出力されます。
Warning: SAFE MODE Restriction in effect. The script whose uid is 500 is not allowed to access /etc/passwd owned by uid 0 in /docroot/script.php on line 2

UID checking. しかし、多くの環境において、厳密な UID チェックは 適切ではなく、より緩やかな GID チェックで十分です。 これは safe_mode_gid スイッチで サポートされます。これを On にすると制限の緩い GID チェックに、 Off (デフォルト) にすると UID チェックになります。

safe_mode の代わりに、 open_basedir ディレクトリを セットすると、全てのファイル操作は特定のディレクトリ配下のみに制限されます。 例えば(Apacheのhttpd.confの例):

<Directory /docroot>   php_admin_value open_basedir /docroot </Directory>
open_basedir でセットしたのと 同じscript.phpを実行すると、以下のような結果になります:
Warning: open_basedir restriction in effect. File is in wrong directory in /docroot/script.php on line 2

特定の関数を無効にすることもできます。 disable_functions ディレクティブは php.ini 以外では使用できないことに注意してください。 つまり、 httpd.conf 上のバーチャルホスト毎あるいはディレクトリ毎に 関数を無効にすることはできない、ということになります。 もし php.ini ファイルに以下を追加した場合:

disable_functions readfile,system
以下のような結果になります:
Warning: readfile() has been disabled for security reasons in /docroot/script.php on line 2

警告

もちろん、これらの PHP の制限はバイナリを実行した場合は有効になりません。