1. ホーム
  2. sql

[解決済み】プリペアドステートメントは、どのようにSQLインジェクション攻撃から保護することができますか?

2022-04-11 09:30:49

質問

どのように 準備されたステートメント を防ぐのに役立ちます。 SQLインジェクション の攻撃を受けたことがありますか?

ウィキペディアによると

プリペアドステートメントは、SQLインジェクションに強いです。 パラメータ値は、後で別の方法で送信されます。 プロトコルを正しくエスケープする必要はありません。元のステートメント テンプレートが外部入力から派生していない場合、SQL インジェクションは起こりません。 が発生します。

理由がよくわからないのですが。簡単な英語と例で説明するとしたら、どのようなことが考えられますか?

どのように解決するのですか?

アイデアは非常にシンプルです - クエリとデータはデータベースサーバーに送信されます。 別々に .

以上です。

SQLインジェクション問題の根源は コードとデータが混在している。

実際、私たちのSQLクエリは 正規のプログラム . そして、そのようなプログラムを動的に作成し、その場でデータを追加しているのです。したがって、そのデータが干渉して プログラムコード SQLインジェクションの例が示すように、SQLインジェクションは、それを変更することさえあります(すべての例はPHP/Mysqlで)。

$expected_data = 1;
$query = "SELECT * FROM users where id=$expected_data";

は、通常のクエリを生成します

SELECT * FROM users where id=1

このコードの間

$spoiled_data = "1; DROP TABLE users;"
$query        = "SELECT * FROM users where id=$spoiled_data";

は、悪意のあるシーケンスを生成します。

SELECT * FROM users where id=1; DROP TABLE users;

これは、プログラム本体に直接データを追加しているため、プログラムの一部となり、データがプログラムを変更する可能性があり、渡されたデータに応じて、通常の出力またはテーブルのいずれかを作成することになります users を削除しました。

一方 プリペアド・ステートメントの場合は、プログラムを変更しないので、そのままです。

そこがポイントですね。

を送信しています。 プログラム をまずサーバーに送信します。

$db->prepare("SELECT * FROM users where id=?");

ここで、データはいくつかの 変数 パラメータやプレースホルダと呼ばれるものです。

全く同じクエリが、データなしでサーバーに送信されることに注意してください! そして、データを送信する際に セカンド のリクエストで、基本的にクエリ自体から分離されています。

$db->execute($data);

というように、プログラムを改変して害を及ぼすことがないようにします。

実にシンプルですね。

いつもどのマニュアルでも省略されていることを、唯一付け加えるとしたら。

プリペアドステートメントで保護できるのは データリテラル 他のクエリパーツと併用することはできません。

そのため、一度、例えば動的な 識別子 - プリペアド・ステートメントでは、例えばフィールド名などには対応できません。私は 最近、この問題について説明した ということで、繰り返さないことにします。