PHPデータのフィルタリングと検証。 よくある間違い

この資料は、主に初心者のWebプログラマーを対象としています。



はじめに



多くの場合、データを保護するために必要なものを理解していない初心者のWebプログラマーによって書かれた自己記述CMSまたはモジュールをインストールしたクライアントからアプローチされます。



ここでは、PHPスクリプトでデータをフィルタリングする際のよくある間違いについて可能な限り説明し、データを正しくフィルタリングする方法について簡単なヒントを示します。



ネットワークにはデータフィルタリングに関する多くの記事がありますが、それらは適切に完全ではなく、詳細な例はありません。



デブリーフィング。



フィルタリング。 エラー番号1


数値変数の場合、次のチェックが使用されます。

$number = $_GET['input_number']; if (intval($number)) { ...  SQL  ... }
      
      





なぜSQLインジェクションにつながるのですか? 実際、ユーザーは変数input_numberで値を指定できます。

 1'+UNION+SELECT
      
      





そのような場合、チェックは成功します。 intval関数は、変数の整数値を取得します。 1、ただし、 $ number変数自体は何も変更されていないため、すべての悪意のあるコードがSQLクエリに転送されます。

適切なフィルタリング:

 $number = intval($_GET['input_number']); if ($number) { ...  SQL  ... }
      
      





もちろん、特定の範囲のみを取得する必要がある場合など、条件は変更できます。

 if ($number >= 32 AND $number <= 65)
      
      







チェックボックスまたは数値を含む複数選択を使用する場合は、次のチェックを実行します。

 $checkbox_arr = array_map('intval', $_POST['checkbox']);
      
      





array_map

また、私は次の形式でフィルタリングに会います:

 $number = htmlspecialchars(intval($_GET['input_number']));
      
      





htmlspecialchars

または:

 $number = mysql_escape_string(intval($_GET['input_number']));
      
      





mysql_escape_string



それは笑顔しか引き起こさない:)



フィルタリング。 間違い#2。


文字列変数の場合、次のフィルタリングが使用されます。

 $input_text = addslashes($_GET['input_text']);
      
      





関数は特別なエスケープを追加します。 ただし、データベースのエンコードは考慮されず、フィルタリングのバイパスが可能です。 この脆弱性を説明した著者のテキストはコピーせず、 Chris Shiflettのリンクを提供するだけです(RuNetで翻訳を検索できます)。



mysql_escape_stringまたはmysql_real_escape_string関数を使用してください、例:

 $input_text = mysql_escape_string($_GET['input_text']);
      
      





htmlタグの発生が予想されない場合は、次のフィルタリングを実行することをお勧めします。

 $input_text = strip_tags($_GET['input_text']); $input_text = htmlspecialchars($input_text); $input_text = mysql_escape_string($input_text);
      
      





strip_tags -htmlタグを削除します。

htmlspecialchars-スペシャルを変換します。 htmlエンティティの文字。

したがって、SQLインジェクションに加えて、XSS攻撃から身を守ります。

ソースコードを出力するためだけにhtmlタグが必要な場合は、次を使用します。

 $input_text = htmlspecialchars($_GET['input_text']); $input_text = mysql_escape_string($input_text);
      
      







変数の値が空でないことが重要な場合は、 trim関数を使用します 。例:

 $input_text = trim($_GET['input_text']); $input_text = htmlspecialchars($input_text); $input_text = mysql_escape_string($input_text);
      
      







フィルタリング。 間違い#3。


データベース内の検索に関するものです。

番号で検索するには、最初のエラーで説明したフィルタリングを使用します。

テキストで検索するには、2番目のエラーで説明したフィルタリングを使用しますが、注意が必要です。

ユーザーが論理エラーを実行できないようにするには、スペシャルを削除または選別する必要があります。 SQL文字。

追加なしの例。 ライン処理:

 $input_text = htmlspecialchars($_GET['input_text']); // : "%" $input_text = mysql_escape_string($input_text);
      
      





出力で、次の形式のリクエストを取得します。

 ... WHERE text_row LIKE '%".$input_text."%' ... // WHERE text_row LIKE '%%%'
      
      





これにより、ベースの負荷が大幅に増加します。

私のスクリプトでは、検索から不要な文字を削除する関数を使用しています。

 function strip_data($text) { $quotes = array ("\x27", "\x22", "\x60", "\t", "\n", "\r", "*", "%", "<", ">", "?", "!" ); $goodquotes = array ("-", "+", "#" ); $repquotes = array ("\-", "\+", "\#" ); $text = trim( strip_tags( $text ) ); $text = str_replace( $quotes, '', $text ); $text = str_replace( $goodquotes, $repquotes, $text ); $text = ereg_replace(" +", " ", $text); return $text; }
      
      





もちろん、上記のすべてのキャラクターが危険なわけではありませんが、私の場合は必要ないので、検索して置き換えます。

フィルタリングの例:

 $input_text = strip_data($_GET['input_text']); $input_text = htmlspecialchars($input_text); $input_text = mysql_escape_string($input_text);
      
      





また、検索の文字数を少なくとも3以上に制限することをお勧めします。 データベースに多数のレコードがある場合、1〜2文字を検索すると、データベースの負荷が大幅に増加します。



フィルタリング。 間違い番号4。


$ _COOKIE変数の値はフィルタリングされません。 一部の人々は、この変数はフォームを介して渡すことができないため、これがセキュリティの保証であると考えています。

この変数は、サイトのCookieを編集することで、どのブラウザーでも非常に簡単に偽造できます。

たとえば、ある有名なCMSで、使用されているサイトテンプレートのチェックがありました。

 if (@is_dir ( MAIN_DIR . '/template/' . $_COOKIE['skin'] )){ $config['skin'] = $_COOKIE['skin']; } $tpl->dir = MAIN_DIR . '/template/' . $config['skin'];
      
      





この場合、変数$ _COOKIE ['skin']の値を置き換えてエラーを発生させることができます。その結果、サイトフォルダーへの絶対パスが表示されます。

Cookieの値を使用してデータベースに保存する場合、上記のフィルタリングのいずれかを使用し、変数$ _SERVERにも適用されます。



フィルタリング。 エラー番号5。


register_globalsディレクティブが含まれています。 オンになっている場合は、必ずオフにしてください。

状況によっては、渡されるべきではない変数の値を渡すことができます。たとえば、サイトにグループがある場合、グループ2は$グループ変数を空または0にする必要がありますが、コードを追加してフォームを偽造するだけです。

 <input type="text" name="group" value="5" />
      
      





PHPスクリプトでは、デフォルト値でスクリプトで宣言されていない場合、 $グループ変数は5になります。



フィルタリング。 間違い番号6。


ダウンロードしたファイルを確認してください。

次の項目を確認してください。

  1. ファイル拡張子 拡張子がphp、php3、php4、php5などのファイルのダウンロードを禁止することをお勧めします。
  2. サーバーにアップロードされたファイルはmove_uploaded_fileです
  3. ファイルサイズ




検証 エラー番号1。


AJAXリクエスト(レピュテーションの増加など)に対してユーザー名またはそのID(レピュテーションを取得する)が転送された場合に直面しましたが、PHP自体にはそのようなユーザーの存在のチェックがありませんでした。

例:

 $user_id = intval($_REQUEST['user_id']); ... INSERT INTO REPLOG SET uid = '{$user_id}', plus = '1' ... ... UPDATE Users SET reputation = reputation+1 WHERE user_id = '{$user_id}' ...
      
      





データベースにレコードを作成していることがわかりますが、これはまったく役に立ちません。



検証 間違い#2。


データを使用してさまざまな種類のアクション(追加、編集、削除)を実行する場合、この機能と追加機能にアクセスするユーザーの権限を確認することを忘れないでください(htmlタグまたは検証なしで素材を公開する機能を使用)。



長い間、あるユーザーが管理メッセージを編集できるフォーラムモジュールで同様のエラーを修正しました。



検証 間違い#3。


複数のphpファイルを使用している場合は、簡単なチェックを行ってください。

index.phpファイル(または他のメインファイル)で、他のphpファイルを接続する前に次の行を記述します。

 define ( 'READFILE', true );
      
      





他のphpファイルの冒頭に次を記述します。

 if (! defined ( 'READFILE' )) { exit ( "Error, wrong way to file.<br><a href=\"/\">Go to main</a>." ); }
      
      





したがって、ファイルへのアクセスを制限します。



検証 間違い番号4。


ユーザーにハッシュを使用します。 これは、XSSによって関数が呼び出されるのを防ぐのに役立ちます。

ユーザーのハッシュを作成する例:

 $secret_key = md5( strtolower( "http://site.ru/" . $member['name'] . sha1($password) . date( "Ymd" ) ) ); // $secret_key -   
      
      





次に、入力をすべての重要な形式の現在のユーザーハッシュの値に置き換えます。

 <input type="hidden" name="secret_key" value="$secret_key" />
      
      





スクリプトチェックの実行中:

 if ($_POST['secret_key'] !== $secret_key) { exit ('Error: secret_key!'); }
      
      







検証 エラー番号5。


SQLエラーを出力するときは、情報へのアクセスを簡単に制限してください。 たとえば、GET変数のパスワードを設定します。

 if ($_GET['passsql'] == "password") { ...  SQL  ... } else { ...    ,   ... }
      
      





これにより、サイトのハッキングに役立つ情報をハッカーから隠すことができます。



検証 エラー番号5。


外部からファイル名を取得して、ファイルを含めないようにしてください。

例:

 if (isset($_GET['file_name'])) { include $_GET['file_name'] .'.php'; }
      
      





スイッチスイッチを使用します。

 switch($_GET['file_name']) { case 'file_1': include 'file_1.php'; break; default: include 'file_0.php'; break; }
      
      





このような場合、提供されなかったファイルの添付を防止します。



ヒント。



信頼性を高めるには、悪意のある文字/データを自分で見逃さないように、既成の人気のあるクラスのいずれかを使用してデータをフィルタリングします。 また、これらのクラスには、多くの場合、データフィルターを選択するオプションがあります。



UPD:投稿を修正しました。 コメントに含まれていた関数と変数に関するすべてのヒントを移動しました。



All Articles