概要

ch04 以降ずっと「値はプレースホルダで渡す」と繰り返してきた理由を、この章で実弾を撃って確認する。SQL インジェクション とは、ユーザー入力に SQL の構文要素 (';--) を紛れ込ませて、開発者の意図しない SQL を DB に実行させる 攻撃で、Web アプリの最古典の脆弱性。情報漏洩・改ざん・テーブル破壊と被害幅も広い。

仕組みは単純で、"WHERE name = '$name'" のように 文字列連結 で SQL を組み立てていると、入力 ' OR '1'='1 を埋めた瞬間に条件が常に真になり 全件返ってくる'; DROP TABLE users; -- を紛れ込ませれば、テーブルを消されることすらある。

これに対するプレースホルダ (prepare + execute) は、SQL の 別ルート で DB に送る方式。DB は最初に「形」をパースして実行計画を作り、後から来た「値」は 常にデータとして扱う。だから '; も SQL 構文として解釈されない。ドリルは危険な連結版 starter をプレースホルダ版に書き直して、両者の違いを手で覚える。

学習目標

ドリル

no 内容
01 文字列連結で書かれた starter を、プレースホルダ版に直す (' 入りの名前で動作確認)
02 検索フォーム想定。LIKE 検索でもプレースホルダを使う

採点用 DB について

採点ランナーは tests/setup.sql を一時 SQLite に流し込み、そのファイルパスを環境変数 DOJO_DB_PATH で渡してきます。受講生コードは次の形で接続してください。

$pdo = new PDO('sqlite:' . getenv('DOJO_DB_PATH'));
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

なぜ文字列連結が危険か

// ❌ 危険: 入力をそのまま SQL に連結
$name = $_GET['name'];
$sql = "SELECT * FROM users WHERE name = '$name'";

ユーザーが name=' OR '1'='1 を入れると、SQL は

SELECT * FROM users WHERE name = '' OR '1'='1'

になり、全件返ってくる。さらに悪意ある入力で '; DROP TABLE users; -- を渡されると、テーブル自体を壊される可能性がある。

プレースホルダ版なら、入力は として扱われるので SQL 構文として解釈されない。

演習: ドリル 01 — 連結をプレースホルダに直す

問題

starter.php はわざと 文字列連結 で SQL を組み立てている。これだと ' (シングルクォート) を含む名前を入れた瞬間に SQL 構文エラーで落ちる。

ターゲット名:

O'Brien

users テーブルに O'Brien (id=1) が登録されている。標準入力からこの名前を受け取り、

1: O'Brien

と出力するように プレースホルダ + prepare/execute で書き直してほしい。

期待される出力

1: O'Brien

ヒント

演習: ドリル 02 — LIKE 検索もプレースホルダで

問題

ユーザーが入力したキーワードで users.name部分一致検索 (LIKE) するコードを書きたい。

users テーブルには次が入っている (setup.sql 参照):

id name
1 山田太郎
2 鈴木花子
3 山本次郎
4 O'Brien

期待される入力

期待される出力

1: 山田太郎
3: 山本次郎

ヒント

この章を AI に聞く

  1. 「ch09 — SQL インジェクション / プリペアド vs 連結」のつまずきやすいポイントを、初学者向けに3つ教えてください

    💬 ChatGPT 📘 Claude ✨ Gemini

  2. 「ch09 — SQL インジェクション / プリペアド vs 連結」について、自分の手で試せる練習問題を3つ出してください (難易度を上げながら)

    💬 ChatGPT 📘 Claude ✨ Gemini

  3. 「ch09 — SQL インジェクション / プリペアド vs 連結」を学んだ後、次に学ぶと良いトピックは何ですか?理由も教えてください

    💬 ChatGPT 📘 Claude ✨ Gemini

🎉 受講お疲れさまでした!

ch09 — SQL インジェクション / プリペアド vs 連結」を読み終えました。
学んだことを誰かに教えると、もっと記憶に残ります。

X で共有 Hatena LINE