[ 原書情報 ]
《SAMS Teach Yourself PHP in 10 Minutes》
著者: Chris Newman
出版社: Sams Publishing
出版日: 2005 年 3 月 29 日
ISBN: 0-672 -32762-7
ページ数: 264
[ 翻訳情報 ]
翻訳者: heiyeluren
翻訳時期: 2006-3-15
翻訳された章: "レッスン 24. PHP セキュリティ"
中国語名: PHP セキュリティ
PHP は間違いなく非常に強力なサーバーサイド スクリプト言語です。しかし、強力な関数には常に重大な危険が伴います。この章では、PHP のセーフ モードを使用して PHP の潜在的な危険の一部を防ぐ方法を学びます。
【セーフ モード】
PHP のセーフ モードは、複数のユーザー アカウントが存在する PHP オープン Web サーバー上に基本的な安全な共有環境を提供します。 PHP が Web サーバー上でセーフ モードで実行されている場合、一部の機能は完全に無効になり、使用可能な機能の一部は制限されます。
[セーフモードを使用して制限を強制する]
セーフモードでは、ファイルシステムにアクセスしようとする一部の機能が制限されます。 Web サーバーのユーザー ID を実行して、特定のファイルを操作するには、そのファイルに対する読み取りまたは書き込みアクセス権が必要です。PHP がこの制限機能を実装することに問題はありません。
セーフ モードがオンになっている場合、ローカル ファイルの読み取りまたは書き込みを試行すると、PHP は現在アクセスしているユーザーがターゲット ファイルの所有者であるかどうかを確認します。所有者でない場合、操作は無効になります。 (書き込み権限: 下位レベルのファイル アクセス権限では、システム オペレーティング システムでのファイルの読み取りまたは書き込みが許可される場合があります。PHP のセーフ モードは、他のユーザーのファイルを操作できないようにするために使用されます。もちろん、Web サーバーグローバル書き込み権限で任意のファイルにアクセスできる可能性があります)
セーフ モードがオンになっている場合、次の関数リストの機能が制限されます:
chdir 、 move_uploaded_file 、 chgrp 、 parse_ini_file 、 chown 、 rmdir 、 copy 、 rename、fopen、require、highlight_file、show_source、include、symlink、link、touch、mkdir、unlink
同様に、PHP 拡張機能の一部の関数も影響を受けます。 (モジュールのロード: dl 機能はセーフ モードでは無効になります。拡張機能をロードしたい場合は、php.ini で拡張機能のオプションを変更し、PHP の起動時にロードするだけです)
PHP セーフ モードがオンになっている場合、オペレーティング システム プログラムを実行する場合、safe_mode_exec_dir オプションで指定されたディレクトリ内のプログラムである必要があります。そうでない場合、実行は失敗します。実行が許可された場合でも、フィルタリングのために自動的にescapeshellcmd関数に渡されます。
コマンドを実行するための次の関数リストが影響を受けます:
exec、shell_exec、passthru、system、popen
さらに、バックマーク演算子 (`) もオフになります。
セーフモードで実行した場合、エラーは発生しませんが、putenv関数は無効になります。同様に、PHP 環境変数を変更しようとする他の関数 set_time_limit や set_include_path も無視されます。
[ セーフ モードをオンにする ]
PHP のセーフ モードをオンまたはオフにするには、php.ini のsafe_mode オプションを使用します。現在 Web サーバーを共有しているすべてのユーザーに対してセーフ モードを有効にしたい場合は、構成オプションを次のように設定します。
safe_mode = On
関数がファイル システムにアクセスするときにファイル所有者のチェックが実行されます。デフォルトでは、ファイル所有者のユーザー ID がチェックされますが、ファイル所有者のグループ ID (GID) を、safe_mode_gid オプションで指定されたものに変更できます。
システムに共有ライブラリ ファイルがある場合、インクルードまたは要求する必要が生じたときに、safe_mode_include_dir オプションを使用してパスを設定し、コードが正常に動作することを確認できます。 (インクルード パス:safe_mode_include_dir オプションを使用してさらに多くのインクルード パスを含める場合は、Unix/Linux システムではコロンを使用して、Windows では include_path オプションと同様にセミコロンを使用して区切ることができます)
たとえば、次のようにしたい場合は、セーフ モードで /usr/local/include/php の下にファイルをインクルードする場合は、オプションを次のように設定できます:
safe_mode_include_dir = /usr/local/include/php
インクルードされたファイルを実行する必要がある場合は、safe_mode_exec_dir オプションを設定できます。たとえば、/usr/local/php-bin パス内のファイルを実行可能にする必要がある場合、オプションを次のように設定できます:
safe_mode_exec_dir = /usr/local/php-bin
(Executable: If the Program実行するファイルが /usr/bin ディレクトリにある場合、指定したオプションで実行できるパスにこれらのバイナリ ファイルを接続できます)
特定の環境変数を設定したい場合は、safe_mode_allowed_env_vars オプションを使用できます。このオプションの値は、環境変数のプレフィックスです。デフォルトでは、PHP_ で始まる環境変数が許可されます。これを変更する場合は、このオプションの値をカンマで区切って設定できます。
たとえば、次の環境変数 TZ でタイムゾーンを許可する場合、このオプションの値を次のように変更します:
safe_mode_allowed_env_vars = PHP_,TZ
【その他のセキュリティ機能】
セーフ モードに加えて、PHP も他にも多くの機能を提供します。PHP を安全に保つための機能です。
[ Hide PHP ]
php.ini で Expose_php オプションを使用すると、Web サーバーから PHP レポート情報が漏洩するのを防ぐことができます。以下のように:
expose_php = オン
この設定全体を使用すると、Web サーバーに対する自動スクリプトからの一部の攻撃をブロックできます。通常、HTTP ヘッダー情報には次の情報が含まれます:
サーバー: Apache/1.3.33 (Unix) PHP/5.0.3 mod_ssl/2.8.16
OpenSSL/0.9.7c
expose_php オプションがオンになった後、PHP上記ヘッダー情報にはバージョン情報は含まれません。
もちろん、ユーザーが Web サイトにアクセスすると、.php ファイル拡張子も表示されます。完全に異なるファイル拡張子を使用したい場合は、httpd.conf で次の行を見つける必要があります:
AddType application/x-httpd .php
.php を任意のファイル拡張子に変更できます。ファイル拡張子はスペースで区切って好きなだけ指定できます。サーバー側で PHP を使用して .html および .htm ファイルを解析する場合は、次のようにオプションを設定します。
AddType application/x-httpd .html .htm
(HTML の解析: Web サーバーを次のように設定します)すべての HTML ファイルを解析するには PHP を使用しますが、サーバー側以外のコードでも解析するために PHP が必要な場合は、サーバーのパフォーマンスに影響します。静的ページに別の拡張子を使用すると、PHP スクリプト エンジンへの依存を排除できます。パフォーマンスを向上させます)
[ ファイル システム セキュリティ ]
セキュリティ モードでは、スクリプト所有者が自分のファイルにのみアクセスできるように制限されますが、open_basedir オプションを使用して、アクセスする必要があるディレクトリを指定できます。ディレクトリを指定すると、PHP はそのディレクトリとそのサブディレクトリ以外のディレクトリへのアクセスを拒否します。 open_basedir オプションはセーフ モード以外でも機能します。
/tmp ディレクトリのみにアクセスするようにファイル システムを制限する場合、設定オプションは次のとおりです:
open_basedir = /tmp
[関数アクセス制御]
disable_functions オプションで関数名を区切るにはカンマを使用できます。その場合、これらの機能は PHP スクリプトでオフになります。この設定はセーフ モード以外でも機能します。
disable_functions = dl
もちろん、disable_classes オプションを使用して一部のクラスへのアクセスをオフにすることもできます。
[ データベース セキュリティ ]
PHP スクリプトに、フォーム値
$sql = "UPDATE mytable SETcol1 = " $_POST["value"] に基づいて実行される MySQL クエリが含まれているとします。 WHERE col2 = 'somevalue'";
$res = mysql_query($sql, $db);
列col1を更新するために、$_POST["value"]に整数値を含めたいとします。ただし、悪意のあるユーザーがフォーム フィールドにセミコロンを入力し、その後に任意に実行したい SQL ステートメントを入力する可能性があります。
たとえば、$_POST["value"] によって送信された値が次のとおりであるとします。 Mysql がクエリを実行すると、次の SQL になります:
UPDATE mytable SET Col1 = 0;
INSERT INTO admin_users (username, password)
VALUES ('me', 'mypassword');WHEREcol2 = 'somevalue';
これは明らかに有害なクエリです。まず、このクエリは mytable テーブルのcol1を更新します。これには、ログインできる新しい管理者を挿入する INSERT 式を実行する 2 番目の式を除いて、何も問題はありません。 3 番目の式は破棄されますが、同時に SQL パーサーは有害なクエリが完了する前にエラーをスローします。この攻撃は、よく SQL インジェクション (注: SQL インジェクション) と呼ばれるものです。
もちろん、SQL インジェクションには問題があります。相手はデータベースの構造を理解している必要があります。この例では、攻撃者は、テーブル admin_users が存在し、そこにユーザー名とパスワードのフィールドが含まれていることを知り、同時に、保存されているパスワードが暗号化されていないことを認識します。
あなた自身を除いて、平均的な Web サイト訪問者はデータベースに関するこの情報を知りません。ただし、ソース コードを開発するオンライン電子商取引プログラムを使用している場合、または無料のディスカッション掲示板プログラムを使用している場合は、これらのデータ テーブルの定義が知られているか、一部のユーザーがデータベースにアクセスできます。
さらに、スクリプト出力ではクエリ エラーが表示されます。これには、データベース構造に関する多くの重要な情報が含まれています。機能している Web サイトでは、display_errors オプションをオフに設定し、display_errors の代わりに log_errors を使用して警告メッセージとエラー メッセージをファイルに挿入することを検討する必要があります。
(データベース権限: これは非常に重要です。スクリプトを介してデータベースに正しく接続するための適切な権限のみが必要です。データベースに接続するためにスクリプト内で管理者を使用しないでください。これを行うと、攻撃者は、他の同一サーバー上の権限を含む、データベースの完全な権限を取得することが可能になります。攻撃者は、GRANT または CREATE USER コマンドを実行して、より多くのアクセス権を取得できるようになります)
SQL インジェクション攻撃を防止したい場合は、ここで送信されたコンテンツは、実行可能な SQL 式ではありません。
前の例では、整数値を使用して更新しました。一重引用符の後に文字列が続く場合、攻撃者は SQL 式全体のセミコロンの前に閉じ引用符を送信する必要があります。ただし、magic_quotes_gpc オプションが有効になっている場合、Web フォームで送信された引用は自動的にエスケープされます。
悪意のある攻撃者による SQL インジェクション攻撃を防ぐには、送信されたデータが合法であることを常に確認する必要があります。必要な値が整数値の場合は、is_numeric 関数を使用して式の値をテストするか、settype 関数を使用して数値に変換し、無駄な SQL ステートメントを排除できます。
SQL 式で複数の値を送信する必要があるプログラムを開発する場合は、sprintf 関数を使用して、データ型の各値を示す書式設定文字を使用して SQL 文字列を構築できます。次の例を見てください:
$sql = sprintf("UPDATE mytable SETcol1 = %d
mysql_escape_string($_POST["string"]) );
前の例では、Mysql データ全体が使用されているため、この文字列は、mysql_escape_string 関数によってフィルタリングされています。他のデータベースの場合は、addslashes 関数を使用してエスケープするか、他の方法を使用できます。