PDO ドキュメントでは、プリペアド ステートメントを使用すると手動でパラメーターを引用する必要がなくなると示唆していますが、答えは微妙なニュアンスで「はい」です。 。」 PDO はデフォルトで MySQL のプリペアド ステートメントをエミュレートしますが、このエミュレーションにより悪用可能な脆弱性が生じる場合があります。
潜在的な脆弱性は、接続エンコーディングに特定の脆弱な文字セット (gbk など) が含まれる場合に発生します。 、cp932) であり、次の条件が満たされています:
そのような場合攻撃者は、無効なマルチバイト文字を含むペイロードを作成し、クライアントで予期される文字セットと実際の文字セットの不一致を悪用する可能性があります。接続の。これにより、生成されたクエリ文字列に引用符で囲まれていない文字が挿入される可能性があり、SQL インジェクションが発生する可能性があります。
予防策:
軽減策:
次のコード スニペットは、安全な方法を示しています。
// PDO without emulated prepares $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $stmt = $pdo->prepare('SELECT * FROM test WHERE name = ? LIMIT 1'); $stmt->execute(array("xbf' OR 1=1 /*")); // PDO with DSN charset parameter $pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=gbk', $user, $password); $stmt = $pdo->prepare('SELECT * FROM test WHERE name = ? LIMIT 1'); $stmt->execute(array("xbf' OR 1=1 /*")); // MySQLi (always uses true prepared statements) $mysqli->query('SET NAMES gbk'); $stmt = $mysqli->prepare('SELECT * FROM test WHERE name = ? LIMIT 1'); $param = "xbf' OR 1=1 /*"; $stmt->bind_param('s', $param); $stmt->execute();
PDO プリペアド ステートメントは、 SQL インジェクションを適切に使用し、安全な方法と組み合わせて効果的に防止します。潜在的な脆弱性を軽減するには、脆弱なエンコードを回避し、エミュレートされた準備を無効にするか、NO_BACKSLASH_ESCAPES モードを有効にすることが重要です。
以上がPDO プリペアド ステートメントは SQL インジェクション攻撃から本当に安全ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。