【ぷりぺあどすてーとめんと】

プリペアドステートメント とは?

最終更新:
💡 SQLの命令と、検索する値を分けて渡す

SQL文のテンプレートを準備し、実行時の値をパラメータとして渡す仕組み。命令と値を分けることでSQLインジェクションを防ぎ、処理の再利用にも役立つ。

📌 このページのポイント
SQLの命令と値を分ける 入力を文字列連結 SQL +入力 入力が命令に混ざる 注入の危険 値をバインド WHERE id = ? 値:42 命令と値を分離 SQLのテンプレート +バインドした値 DB テーブル名や命令語は別に扱う 性能はDB・ドライバー・設定による
値をSQLへ連結せず、パラメータとして渡す。別の部分に入力を連結すれば危険は残り、テーブル名などは値のパラメータで置き換えられない。
ひよこ ひよこ
何を準備してるの?
ペンギン先生 ペンギン先生
SQL文のテンプレートだよ。例えばSELECT name FROM users WHERE id = ? のように値を渡す場所を作り、実行時にidの値を渡す。? や :name、$1など、使える表記はDBやAPIによって違うよ。
ひよこ ひよこ
それでSQLインジェクションを防げるの?
ペンギン先生 ペンギン先生
バインドした入力は命令ではなく値として扱われるので、その入力でSQLの構造を変えられなくなるんだ。ただし別の部分に入力を文字列としてつなげたら、そこから注入される危険は残るよ。
ひよこ ひよこ
テーブル名も ? にできる?
ペンギン先生 ペンギン先生
値のパラメータは、テーブル名・列名・ASCなどの命令語の代わりには使えないよ。そうした部分を選ばせるなら、プログラム側で用意した許可された候補に対応させる。入力をそのままSQLへつなげないことが大切だね。
ひよこ ひよこ
同じ文を使えば、必ず速くなる?
ペンギン先生 ペンギン先生
解析などの繰り返しを減らせるけれど、必ず速くなるとは限らないよ。PostgreSQLは値に応じた計画を作る場合もあり、計画の作成が常に1回という説明はできない。PDOにはクライアント側で準備を模倣する実装もあるので、DBやDB接続用ライブラリの動作を確認するんだ。
ひよこ ひよこ
ORMを使っていたら大丈夫?
ペンギン先生 ペンギン先生
ライブラリ名だけでは判断できないよ。値をバインドしているか、生SQLの部分で入力を連結していないかを確認する。LIKEの % や _ を文字として検索したい場合も、SQL命令の注入対策とは別に、パターンとしての意味を扱う必要があるよ。
ペンギン
まとめ:ざっくりこれだけ覚えればOK!
「プリペアドステートメント」って出てきたら「SQLの命令と値を分けて実行する仕組み」と思えばだいたいOK!
📖 おまけ:英語の意味
「Prepared Statement」 = 事前に準備された文
💬 Prepared(準備された)Statement(文)で、SQL文をあらかじめ準備しておくという意味だよ

参考資料

← 用語集にもどる