インクルードの乱用
1. 脆弱性の原因:
Include は、PHP Web サイトを作成する際に最も一般的に使用される関数であり、相対パスをサポートします。入力変数を Include パラメータとして直接使用する PHP スクリプトが多数あり、任意のスクリプト参照や絶対パスの漏洩などの脆弱性が発生します。次のコードを見てください。
...
$includepage=$_GET["includepage"];
include($includepage);
...
明らかに、目的のページを取得するには、さまざまな Includepage 変数を送信するだけで済みます。存在しないページを送信すると、PHP スクリプトでエラーが発生し、実際の絶対パスが漏洩する可能性があります (この問題の解決策は次の記事で説明されています)。
2. 脆弱性の解決:
この脆弱性に対する解決策は非常に簡単で、まずページが存在するかどうかを確認してから、そのページを含めることです。より厳密には、配列を使用して、含めることができるファイルを指定します。次のコードを見てください。
$pagelist=array("test1.php","test2.php","test3.php"); //これは含めることができるファイルを指定します
if(isset($_GET["includepage"])) //$includepage があるかどうかを判定する
{
$includepage=$_GET["includepage"];
foreach($pagelist として $prepage)
{
if($includepage==$prepage) //ファイルが許可リストにあるかどうかを確認します
{
インクルード($prepage);
$checkfind=true;
壊す;
}
}
if($checkfind==true){ unset($checkfind) }
else{ die("無効な参照ページです!");
}
これで問題は非常にうまく解決されます。
ヒント: この問題が発生する関数には、require()、require_once()、include_once()、readfile() などが含まれます。作成時にも注意する必要があります。
入力変数はフィルタリングされません
1. 脆弱性の原因:
この脆弱性は ASP に以前から存在しており、当時は無数のインジェクション脆弱性を引き起こしていました。しかし、当時は PHP の影響力が小さかったため、これに注目する人は多くありませんでした。 PHP の場合、より多くの PHP スクリプトがテキスト データベースを使用するため、この脆弱性の影響は ASP の影響よりも大きくなります。もちろん、SQL ステートメント インジェクションの問題もあります。より古典的な例を挙げると、最初はデータベースです。
$id=$_GET["id"];
$query="SELECT * FROM my_table where id='".$id."'"; //非常に古典的な SQL インジェクションの脆弱性
$result=mysql_query($query);
ここで、インジェクションを使用してデータベースの他の内容を取得できることは明らかです。ここでは詳しく説明しませんが、ASP インジェクションと同様に、以前のブラック ディフェンスを参照してください。次に、テキスト データベースの問題を見てみましょう。
$text1=$_POST["text1"];
$text2=$_POST["text2"];
$text3=$_POST["text3"];
$fd=fopen("test.php","a");
fwrite($fd,"rn$text1&line;$text2&line;$text3");
fclose($fd);
テキストの脆弱性はおそらくさらに深刻です。送信された変数に小さな PHP コードを挿入すると、このテキスト データベース test.php を PHP バックドアに変えることができます。アップロード コードを挿入するだけでも、完全な PHP バックドアをアップロードできます。次に、権限を増やすと、サーバーがあなたのものになります。
2. 脆弱性の解決:
この脆弱性に対する解決策は実際には非常に簡単で、送信されたすべての変数を厳密にフィルタリングすることです。一部の機密性の高い文字を置き換えます。 PHP が提供する htmlspecialchars() 関数を使用して、HTML のコンテンツを置き換えることができます。以下に例を示します。
//フィルター関数を構築www.knowsky.com
関数 flt_tags($text)
{
$badwords=array("Fuck you","Fuck"); //ワードフィルターリスト
$text=rtrim($text);
foreach($badwords as $badword) //ここで語彙をフィルタリングします
{
if(stristr($text,$badword)==true){ die("エラー: 送信したコンテンツには機密性の高い言葉が含まれています。機密性の高いコンテンツは送信しないでください。");
}
$text=htmlspecialchars($text); //HTML の置換
//これらの 2 行はキャリッジ リターンを
$text=str_replace("r","
に置き換えます)
",$text);
$text=str_replace("n","",$text);
$text=str_replace("&line;","│",$text); //テキストデータベースの区切り文字「&line;」を全角の「│」に置き換えます。
$text=preg_replace("/s{ 2 }/"," ",$text);
$text=preg_replace("/t/"," ",$text); // 引き続きスペースを置換します。
if(get_magic_quotes_gpc()){ $text=stripslashes($text) } //magic_quotes がオンの場合は、' を置き換えます。
$text を返します。
text1
=$_POST["text1"];
$text2=$_POST["text2"];
$text3=$_POST["text3"];
//すべての入力をフィルタリングします。
$text1=flt_tags($text1);
$text2=flt_tags($text2);
$text3=flt_tags($text3);
$fd=fopen("test.php","a");
fwrite($fd,"rn$text1&line;$text2&line;$text3");
fclose($fd);
いくつかの置換とフィルタリングを行った後、データをテキストまたはデータベースに安全に書き込むことができます。
管理者の判断が不完全
1. 脆弱性の原因:
PHP を使用してスクリプトを作成しますが、これには通常、管理者権限が必要です。一部のスクリプトは、管理者権限に対して「はい」の判定のみを行い、「いいえ」の判定を無視することがよくあります。 PHP 設定ファイルで register_globals がオンになっている場合 (4.2.0 以降のバージョンではデフォルトでオフになっていますが、便宜上オンにしている人も多く、これは非常に危険な動作です)、変数が偽装のために送信される状況が発生します。管理者。コード例を見てみましょう。
$cookiesign="admincookiesign" //管理者の Cookie 変数かどうかを決定します。
$adminsign=$_COOKIE["sign"]; // ユーザーの Cookie 変数を取得します
if($adminsign==$cookiesign)
{
$admin=true;
if
($admin){ echo "あなたは管理者になりました。";
とても安全そうです(笑)。ここで、PHP 構成ファイルで register_globals がオンになっていると仮定します。 「test.php?admin=true」というアドレスを送信しましたが、結果を見ましたか?正しい Cookie はありませんが、register_globals がオンになっているため、送信した管理変数は自動的に true として登録されます。さらに、スクリプトには「いいえ」の判定がないため、admin=true によって管理者権限を正常に取得できます。この問題はほとんどの Web サイトやフォーラムに存在します。
2. 脆弱性の解決:
この問題を解決するには、スクリプトに管理者に対する「いいえ」の判断を追加するだけです。ここでは、PHP 構成ファイルで register_globals がオンになっていると仮定します。コードを見てください。
$cookiesign="admincookiesign" //管理者の Cookie 変数かどうかを決定します。
$adminsign=$_COOKIE["sign"]; // ユーザーの Cookie 変数を取得します
if($adminsign==$cookiesign)
{
$admin=true;
}
それ以外
{
$admin=false;
}
if($admin){ echo "あなたは管理者になりました。";
このようにして、攻撃者が正しい Cookie なしで変数 admin=true を送信したとしても、スクリプトは今後の判断で $admin を False に設定します。これで問題の一部が解決されます。ただし、$admin は変数であるため、将来的に他のスクリプト参照に抜け穴が発生し、$admin が再割り当てされると、新たな危機が発生します。したがって、管理者権限の決定を保存するには定数を使用する必要があります。 Define() ステートメントを使用して、管理者権限を記録するための管理定数を定義します。この後に再割り当てすると、エラーが発生し、保護の目的が達成されます。次のコードを見てください。
$cookiesign="admincookiesign" //管理者の Cookie 変数かどうかを決定します。
$adminsign=$_COOKIE["sign"]; // ユーザーの Cookie 変数を取得します
if($adminsign==$cookiesign)
{
定義(管理者、true);
}
それ以外
{
定義(管理者、偽);
}
if(admin){ echo "現在管理者ステータスです。";
Define ステートメントを使用するので、Admin 定数を呼び出すときは、変数記号 $ を習慣的に先頭に追加せず、Admin と !admin を使用することに注意してください。
テキストデータベースが公開される
1. 脆弱性の原因:
前述したように、テキスト データベースは柔軟性が高いため、外部サポートは必要ありません。さらに、PHP は非常に強力なファイル処理機能を備えているため、テキスト データベースが PHP スクリプトで広く使用されています。テキスト データベースを使用する優れたフォーラム プログラムもいくつかあります。ただし、得もあれば損もあり、テキスト データベースのセキュリティは他のデータベースに比べて低くなります。
2. 脆弱性の解決:
テキスト データベースは、MDB と同様にダウンロードできる通常のファイルとして機能します。したがって、MDB と同じ方法でテキスト データベースを保護する必要があります。テキスト データベースのサフィックス名を .PHP に変更します。そしてデータベースの最初の行に結合します。このようにして、テキスト データベースは PHP ファイルとして扱われ、実行は最初の行で終了します。つまり、テキスト データベースを保護する目的を達成するために、空のページが返されます。
間違ったパスが漏洩しました
1. 脆弱性の原因:
PHP でエラーが発生すると、エラー スクリプトの場所、行番号、および理由が表示されます。次に例を示します。
注意: 未定義の定数テストの使用 - D:interpubbigflytest.php の 3 行目で「test」とみなします
大したことではないという人も多い。しかし、実際のパスが漏洩した場合の影響は、一部の侵入者にとっては想像を絶するものであり、実際、多くのサーバーがこの問題を抱えています。
ネットワーク管理者の中には、PHP 設定ファイルの display_errors を Off に設定するだけで問題を解決する人もいますが、私はこの方法はあまりにも消極的だと思います。場合によっては、デバッグのために PHP がエラー情報を返す必要があることがあります。また、何か問題が発生した場合は、ユーザーに説明したり、別のページに移動したりする必要がある場合もあります。
2. 脆弱性の解決:
PHP は 4.1.0 以降、カスタム エラー処理ハンドル関数 set_error_handler() を提供していますが、これを知っているスクリプト作成者はほとんどいません。多くの PHP フォーラムの中で、この状況に対処しているのを見たことがありません。 set_error_handler の使用法は次のとおりです。
string set_error_handler (コールバック error_handler [, int error_types])
ここで、カスタム エラー処理を使用して実際のパスを除外します。
//Admin は管理者の ID 決定であり、true は管理者です。
//カスタム エラー処理関数には、これらの 4 つの入力変数 $errno、$errstr、$errfile、$errline が必要です。そうでない場合は無効になります。
関数 my_error_handler($errno,$errstr,$errfile,$errline)
{
// 管理者ではない場合は、実際のパスをフィルタリングします
if(!管理者)
{
$errfile=str_replace(getcwd(),"",$errfile);
$errstr=str_replace(getcwd(),"",$errstr);
スイッチ
($errno)
{
ケース E_エラー:
echo "エラー: [ID $errno] $errstr (行: $errfile の $errline)
n";
echo "プログラムの実行が停止しました。管理者に連絡してください。";
//エラーレベルのエラーが発生した場合はスクリプトを終了します
出口;
ブレーク;
ケース E_WARNING:
echo "警告: [ID $errno] $errstr (行: $errfile の $errline)
n";
ブレーク;
デフォルト:
//通知レベルのエラーを表示しない
壊す;
}
}
// my_error_handler 関数にエラー処理を設定します
set_error_handler("my_error_handler");
…
このようにして、セキュリティとデバッグの利便性の間の矛盾をうまく解決できます。また、Web サイトのスタイルに合わせてエラー メッセージをより美しくすることも考えられます。ただし、次の 2 つの点に注意してください。
(1) E_ERROR、E_PARSE、E_CORE_ERROR、E_CORE_WARNING、E_COMPILE_ERROR、および E_COMPILE_WARNING は、このハンドルでは処理されません。つまり、最もオリジナルの方法で表示されます。ただし、これらのエラーはコンパイル エラーまたは PHP カーネル エラーによって発生するものであり、通常の状況では発生しません。
(2) set_error_handler()使用後は、error_reporting()が無効になります。つまり、すべてのエラー (上記のエラーを除く) は、処理のためにカスタム関数に渡されます。
set_error_handler() に関するその他の情報については、公式 PHP マニュアルを参照してください。
POST の脆弱性
1. 脆弱性の原因:
前に述べたように、変数を登録するために register_globals に依存するのは悪い習慣です。一部のゲストブックやフォーラム プログラムでは、ページの取得方法や投稿の間隔をさらに厳密にチェックする必要があります。スパム投稿や外部からの投稿を防ぐため。ゲストブック プログラムの次のコードを見てみましょう。
...
$text1=flt_tags($text1);
$text2=flt_tags($text2);
$text3=flt_tags($text3);
$fd=fopen("data.php","a");
fwrite($fd,"rn$text1&line;$text2&line;$text3");
fclose($fd);
...
URL「post.php?text1=testhaha&text2=testhaha&text3=testhaha」を送信すると明らかになります。データは通常どおりファイルに書き込まれます。このプログラムは、変数のソースとブラウザがどのようにページを取得したかを検出しません。このページに複数の投稿を送信すると、フラッディングが発生します。この脆弱性を利用してフォーラムやゲストブックに広告を掲載するソフトウェアも存在しており、これは恥ずべき行為です(友人のゲストブックは1週間で10ページ以上の書き込みがあり、どうしようもありませんでした)。
2. 脆弱性の解決:
データを処理して保存する前に、まずブラウザがページを取得する方法を決定します。 $_SERVER["REQUEST_METHOD"] 変数を使用して、ブラウザのページ取得方法を取得します。 「POST」になっているか確認してください。スクリプトでセッションを使用して、ユーザーが通常のチャネル (つまり、送信コンテンツが入力されるページ) を通じてデータを送信したかどうかを記録します。または、$_SERVER["HTTP_REFERER"] を使用してこれを検出しますが、これはお勧めできません。一部のブラウザは REFERER を設定しないため、一部のファイアウォールも REFERER をブロックします。さらに、送信されたコンテンツをチェックして、データベース内に重複したコンテンツがないかどうかを確認する必要もあります。ゲストブックを例として、Session を使用して決定します。
閲覧コンテンツを入力するページのフロントエンドに以下を追加します。
$_SESSION["allowgbookpost"]=time(); //登録が行われた時刻。メッセージデータを受け付けて保存するページでは、データ処理の前にSessionを使用して次の処理も実行します。
if(strtoupper($_SERVER["REQUEST_METHOD"])!="POST"){ die("エラー: 外部から送信しないでください。") } //ページ取得方法がPOSTかどうかを確認します。
if(!isset($_SESSION["allowgbookpost"]) または (time()-$_SESSION["allowgbookpost"] < 10)){ die("エラー: 外部から送信しないでください。") } // メッセージを確認します。記入する際の時間
if(isset($_SESSION["gbookposttime"]) and (time()-$_SESSION["gbookposttime"] < 120)){ die("エラー: 2 回のメッセージ送信の間隔は 2 分以上である必要があります。 "); } //メッセージ間隔を確認します
unset($_SESSION["allowgbookpost"]); //一度に複数の投稿が入力ページに入らないように、allowgbookpost 変数の登録を解除します
$_SESSION["gbookposttime"]=time(); //スパムや悪意のある攻撃を防ぐためにメッセージを送信する時間を登録します。
...
データの処理と保存
...
このような複数のレビューの後、プログラムはより安全になります。