章: 第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 を安全に扱うための基本パターンを学びます。