ホームページ  >  記事  >  バックエンド開発  >  PHPでのSQLインジェクションを防ぐ方法

PHPでのSQLインジェクションを防ぐ方法

WBOY
WBOYオリジナル
2016-07-25 08:58:54944ブラウズ
  1. $unsafe_variable = $_POST['user_input'];
  2. mysql_query("INSERT INTO table (column) VALUES ('" . $unsafe_variable . "')");
コードをコピー

これはユーザーは VALUE "); DROP TABLE table; - のようなものを入力できるため、クエリは次のようになります。

  1. INSERT INTO table (column) VALUES('VALUE'); '
コードをコピー

この状況を回避するにはどうすればよいですか? 準備されたステートメントとパラメーター化されたクエリを使用します。パラメータを含む SQL ステートメントはデータベース サーバーに送信され、解析されます。攻撃者が悪意を持って SQL を挿入することは不可能です。 次の 2 つのオプションがあります。 1. PDO (PHP データ オブジェクト) を使用します。

  1. $stmt = $pdo->prepare('SELECT * FROM従業員 WHERE name = :name');
  2. $stmt->execute(array(':name' => $name)) ;
  3. foreach ($stmt as $row) {
  4. // $row で何かをする
  5. }
コードをコピー

SQL インジェクションを防ぐための PDO の使い方の詳細については、次を参照してください: PDO の使い方を学ぶSQL インジェクションのリスクを回避するために MySQL にクエリを実行します。

2.mysqli を使用します。

  1. $stmt = $dbConnection->prepare('SELECT * FROM従業員 WHERE name = ?');
  2. $stmt->bind_param('s', $name);
  3. $stmt-> execute();
  4. $result = $stmt->get_result();
  5. while ($row = $result->fetch_assoc()) {
  6. // $row で何かをする
  7. }
コードをコピー

PDO (PHP データオブジェクト) PDO を使用して mysql データベースにアクセスする場合、デフォルトでは実際のプリペアド ステートメントは使用されないことに注意してください。この問題を解決するには、準備されたステートメントのエミュレーションを無効にする必要があります。

PDO を使用して接続を作成する例は次のとおりです。

  1. $dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');
  2. $dbConnection->setAttribute(PDO:: ATTR_EMULATE_PREPARES, false);
  3. $dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
コードをコピー

上記の例では、エラー モード ERRMODE は厳密には必要ありませんが、次のことをお勧めします。追加してください。このメソッドは、致命的なエラーが発生した場合でもスクリプトを停止しません。そして、開発者にエラー (PDOException がスローされたとき) を捕捉する機会を与えます。 setAttribute() 行は必須で、エミュレートされたプリペアド ステートメントを無効にし、実際のプリペアド ステートメントを使用するように PDO に指示します。これにより、ステートメントと値が MySQL データベース サーバーに送信される前に PHP によって解析されなくなります (攻撃者が悪意のある SQL を挿入する機会がなくなりました)。 もちろん、コンストラクター オプションで文字セット パラメーターを設定できます。特に、「古い」PHP バージョン (5.3.6) では DSN の文字セット パラメーターが無視されることに注意してください。

説明 渡した SQL プリペアド ステートメントがデータベース サーバーによって解析およびコンパイルされるとどうなりますか?文字 (上記の例では、? や :name など) を指定して、データベース エンジンにフィルタリングする内容を伝え、execute を呼び出して、指定したパラメーター値と組み合わせて準備されたステートメントを実行します。

ここで最も重要なことは、パラメータ値が SQL 文字列ではなく、プリコンパイルされたステートメントと結合されることです。SQL インジェクションは、悪意のある文字列を含む SQL スクリプトを不正に作成し、それをデータベースに送信することによって機能します。個別の SQL パラメータを使用すると、リスクが軽減されます。プリペアド ステートメントを使用する場合、送信するパラメータは文字列としてのみ扱われます (ただし、データベース エンジンはパラメータの最適化を行う場合がありますが、上記ではもちろん最終的には数値になる可能性があります)。たとえば、変数 $name に「sarah';DELETE * FROMemployees」が含まれている場合、結果は検索文字列「'sarah';DELETE * FROMemployees」のみとなり、空のサーフェスは得られません。

もう 1 つの利点: 同じセッション内で同じステートメントが複数回実行された場合、解析とコンパイルは 1 回だけ行われます。 例 (PDO を使用):

  1. $preparedStatement = $db->prepare('INSERT INTO table (column) VALUES (:column)');
  2. $preparedStatement->execute(array(':column' => $unsafeValue ));
コードをコピー

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