[解決済み] PHPでSQLインジェクションを防ぐにはどうしたらいいですか?
質問
ユーザ入力がSQLクエリにそのまま挿入された場合、アプリケーションは以下のような脆弱性を持つことになります。 SQLインジェクション 次の例のように。
$unsafe_variable = $_POST['user_input'];
mysql_query("INSERT INTO `table` (`column`) VALUES ('$unsafe_variable')");
それは、ユーザーが次のような入力ができるからです。
value'); DROP TABLE table;--
となり、クエリーは
INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table;--')
このような事態を防ぐには、どうしたらよいのでしょうか?
解決方法は?
その 正しい SQL インジェクション攻撃を回避する方法は、どのデータベースを使用する場合でも、次のとおりです。 データとSQLを分離する そうすれば、データはデータのままであり 解釈されることはない をSQLパーサがコマンドとして処理します。正しくフォーマットされたデータ部分でSQL文を作成することは可能ですが 完全に 詳細を理解するためには、常に プリペアドステートメントとパラメータ化されたクエリを使用します。 これらは、パラメータとは別にデータベースサーバーに送信され、解析されるSQL文です。こうすることで、攻撃者が悪意のあるSQLを注入することは不可能になります。
これを実現するためには、基本的に2つの選択肢があります。
-
使用方法 PDO (サポートされているデータベースドライバの場合)。
$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name'); $stmt->execute([ 'name' => $name ]); foreach ($stmt as $row) { // Do something with $row }
-
使用方法 MySQLi (MySQL用)です。
$stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?'); $stmt->bind_param('s', $name); // 's' specifies the variable type => 'string' $stmt->execute(); $result = $stmt->get_result(); while ($row = $result->fetch_assoc()) { // Do something with $row }
MySQL 以外のデータベースに接続する場合は、ドライバ固有の 2 番目のオプションがあるので、それを参照する(たとえば。
pg_prepare()
と
pg_execute()
PostgreSQLの場合)。PDOは世界共通のオプションです。
正しい接続設定
を使用する場合は注意が必要です。 PDO を使用して、MySQL データベースにアクセスします。 リアル プリペアドステートメントは デフォルトで使用されない . これを修正するには、プリペアドステートメントのエミュレーションを無効にする必要があります。を使用して接続を作成する例です。 ピーディーオー があります。
$dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'password');
$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
上記の例では、エラーモードは厳密には必要ではありません。
を追加することをお勧めします。
. こうすることで、スクリプトが
Fatal Error
というのは、何か問題が発生したときです。そして開発者に
catch
というエラーは
throw
として
PDOException
s.
とは
必須
しかし、最初の
setAttribute()
この行は PDO に対して、エミュレートされたプリペアドステートメントを無効にして
リアル
準備されたステートメント。これにより、ステートメントとその値が MySQL サーバーに送信される前に PHP によって解析されないことを確認します (攻撃者が悪意のある SQL を注入する機会を与えないようにします)。
を設定することができますが
charset
をコンストラクタのオプションで指定することができますが、 「古い」バージョンの PHP (5.3.6 以前) では
charset パラメータは無視されます。
を DSN で使用します。
説明
に渡すSQL文は
prepare
はデータベースサーバーによってパースされ、コンパイルされます。パラメータを指定することで (
?
のような名前付きパラメータ、または
:name
の例では、) データベースエンジンに、どこをフィルタリングしたいのかを伝えます。そして
execute
を指定すると、プリペアド・ステートメントに指定したパラメータ値が組み合わされる。
ここで重要なのは、パラメータ値はSQL文字列ではなく、コンパイルされた文と結合されるということです。SQLインジェクションは、スクリプトがデータベースに送信するSQLを作成する際に、悪意のある文字列を含めるように仕向けることで機能します。ですから、実際のSQLをパラメータとは別に送信することで、意図しないものができてしまうリスクを抑えることができるのです。
プリペアドステートメントを使うときに送るパラメータはすべて文字列として扱われます(もちろん、データベースエンジンは最適化を行うので、パラメータが数値になってしまうこともあります)。上の例では、もし
$name
変数に
'Sarah'; DELETE FROM employees
という文字列を検索することになります。
"'Sarah'; DELETE FROM employees"
で終わることはありません。
空のテーブル
.
プリペアドステートメントを使うもう一つの利点は、同じセッションで同じステートメントを何度も実行しても、パースとコンパイルは一度だけなので、ある程度のスピードアップが図れることです。
それから、インサートの方法について質問があったので、ここに例を示します(PDOを使用)。
$preparedStatement = $db->prepare('INSERT INTO table (column) VALUES (:column)');
$preparedStatement->execute([ 'column' => $unsafeValue ]);
プリペアドステートメントは動的クエリに使用できますか?
クエリパラメータにプリペアドステートメントを使用することはできますが、ダイナミッククエリの構造そのものをパラメータ化することはできませんし、特定のクエリ機能をパラメータ化することもできません。
これらの特定のシナリオのために、可能な値を制限するホワイトリストフィルタを使用することが最善です。
// Value whitelist
// $dir can only be 'DESC', otherwise it will be 'ASC'
if (empty($dir) || $dir !== 'DESC') {
$dir = 'ASC';
}
関連
-
[解決済み】PHP - 構文エラー、予期しないT_CONSTANT_ECAPSED_STRING [閉店].
-
[解決済み】phpMyAdmin: シークレットパスフレーズ?
-
[解決済み] [Solved] Fatal error: 非オブジェクトのメンバ関数fetch_assoc()の呼び出し [重複]。
-
[解決済み] SQL ServerでSELECTからUPDATEする方法とは?
-
[解決済み] MySQLでコマンドラインを使用してSQLファイルをインポートするにはどうすればよいですか?
-
[解決済み] PHPでユーザー入力をサニタイズするにはどうすればよいですか?
-
[解決済み] mysql_real_escape_string() を回避する SQL インジェクション
-
[解決済み] PDOのプリペアドステートメントは、SQLインジェクションを防ぐのに十分ですか?
-
[解決済み】XKCDコミック「Bobby Tables」のSQLインジェクションはどのように動作するのでしょうか?
-
[解決済み] リファレンス - このシンボルはPHPで何を意味するのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】Weird PHP error: 'Can't use function return value in write context'.
-
[解決済み] 整形されていない数値が発生しました。
-
[解決済み] SAJAXは死んだか?何を置き換えるべきか?
-
[解決済み】新しいPHPMailerはPHPMailerAutoload.phpが必要?
-
[解決済み】「Fatal error: Class 'MySQLi' not found "を解決するには?
-
[解決済み】未定義のメソッド mysqli_stmt::get_result を呼び出す。
-
[解決済み】PHPのクラスが見つからないが、インクルードされている
-
[解決済み] Uncaught Error: 未定義の関数 mysql_escape_string() の呼び出し。
-
[解決済み】mysqli::query(): mysqli をフェッチできない
-
[解決済み】MySQLへの挿入時にPHPでシングルクォートをエスケープする【重複あり