第42回: SQLインジェクション対策 — 悪意ある入力からDBを守る一手

章: 第5章: Web・DB・セキュリティ

ユーザーが入力した文字列をそのままSQLに組み込んでいませんか?それは致命的なリスクです。

問題と解決策

"SELECT * FROM users WHERE id = " . $_GET['id'] のような直接連結は、1 OR 1=1 のような悪意ある文字列を入力されると全データを返してしまいます。さらに ;DROP TABLE users のような破壊的な命令も実行できてしまいます。

解決策はプリペアドステートメントです。SQLの構造とデータを分離してDBエンジンに送ることで、入力値がSQL命令として解釈されなくなります。

危険な実装 vs 安全な実装

実装パターン リスク 推奨度
文字列直接連結 SQLインジェクション高リスク ❌ 使用禁止
addslashes() によるエスケープ 不完全・回避されやすい ❌ 非推奨
PDO::quote() 改善されるが漏れの可能性あり △ 限定的
プリペアドステートメント SQL構造とデータを完全分離 ✅ 推奨

チェックポイント: $stmt->execute([':email' => $email]) の形で値を渡していますか?プレースホルダーに直接連結している場合はプリペアドステートメントの意味がなくなります。

コードサンプル


<?php
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
$stmt->execute(['email' => $email]);

まとめ & 次のステップ

  • ユーザー入力をSQLに直接連結するのは絶対に避けましょう
  • プリペアドステートメントでSQLの構造とデータを分離します
  • :name? のプレースホルダーを使い、値は execute() で渡します
  • PDOの設定で ERRMODE_EXCEPTION を有効にしてエラーを見逃さないようにします

次回は フォーム受け取り$_POST$_GET を安全に扱うための基本パターンを学びます。

Related Articles