PHP のセーフモードは、共有サーバでのセキュリティの問題を解決するための試みです。
この問題を PHP のレベルで解決しようとするのはアーキテクチャ上正しくありません。
しかし、Web サーバや OS レベルでの代替策はあまり現実的ではないため、
多くのユーザ、特に ISP ではセーフモードが現在使用されています。
セキュリティとセーフモード
セキュリティとセーフモード設定ディレクティブ
| 名前 |
デフォルト |
変更の可否 |
変更履歴 |
| safe_mode |
"0" |
PHP_INI_SYSTEM |
PHP 6.0.0 で削除。 |
| safe_mode_gid |
"0" |
PHP_INI_SYSTEM |
PHP 4.1.0 から利用可能。PHP 6.0.0 で削除。 |
| safe_mode_include_dir |
NULL |
PHP_INI_SYSTEM |
PHP 4.1.0 から利用可能。PHP 6.0.0 で削除。 |
| safe_mode_exec_dir |
"" |
PHP_INI_SYSTEM |
PHP 6.0.0 で削除。 |
| safe_mode_allowed_env_vars |
"PHP_" |
PHP_INI_SYSTEM |
PHP 6.0.0 で削除。 |
| safe_mode_protected_env_vars |
"LD_LIBRARY_PATH" |
PHP_INI_SYSTEM |
PHP 6.0.0 で削除。 |
| open_basedir |
NULL |
PHP_INI_ALL |
PHP < 6 では 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() や gzopen()
を使ってスクリプトがファイルをオープンしようとすると、
そのファイルの位置がチェックされます。
指定されたディレクトリツリーの範囲外にあった場合、PHP はオープンを拒否します。
全てのシンボリックリンクは解決されるので、
シンボリックリンクを使ってこの制限を回避することは不可能です。
ファイルが存在しない場合はシンボリックリンクの解決は行われず、
ファイル名の比較は open_basedir
に対して行われます。
.は特別な値で、
スクリプトが格納されているワーキングディレクトリをベースディレクトリとして
使用することを意味します。
これは、しかし、スクリプトのワーキングディレクトリが
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 の制限はバイナリを実行した場合は有効になりません。