SQLインジェクション入門:仕組みと対策
UNIONで別の問い合わせをくっつける
この回でやること
条件を書き換えるだけでなく、別のSELECTの結果を元の結果に縦につなぐUNIONを見ます。列の数と型が合わないと成り立たない、という一点が肝です。
- 読む 約 7 分
- 最後にクイズ 1 問
このレッスンで学ぶこと
UNION は、元の結果の後ろに別のSELECTを縦につなぎ、その中身を同じ画面へ運び出す命令です。この回はUNIONが何をするのかと、成り立たせるために必ず満たす条件を、同じ users テーブルで見ます。
読み終えると、なぜ列の数と型が合わないと文ごと落ちるのかを、UNIONの仕組みから説明できるようになります。
UNIONは結果を縦に積む
UNION は、前のSELECTが返した行の下に、後のSELECTが返した行を積み重ね、1つの結果として返します。たとえば名前で探す画面が、内部でこう組み立てているとします。
SQL クエリ
SELECT name, role FROM users WHERE name = 'tanaka'この後ろに自分のSELECTをつなぐと、元の1行に続けて、好きな問い合わせの結果を運び出せます。画面が name の列を表示する作りなら、そこへ別の値を流し込めます。
SQL クエリ
SELECT name, role FROM users
WHERE name = 'tanaka'
UNION SELECT password, role FROM users --'つないだ後半は、users 全員のパスワードを name の位置に並べます。画面は name のつもりでそれを表示するので、パスワードが名前の欄に現れます。条件を真偽で操るのが前回までの話なら、UNIONは表示される中身そのものを差し替える手です。
揃わないと文ごと落ちる
UNIONには厳しい条件が2つあります。前後のSELECTで 列の数が同じ であること、そして対応する列の 型が揃う ことです。
SQL クエリ
SELECT name, role FROM users UNION SELECT password FROM usersこれは前が2列、後ろが1列で数が合わないため、データベースは積めずに文全体をエラーにします。数が合っても、文字列の列に数値の列を重ねるなど型が食い違うと、製品によっては同じようにエラーになります。だから攻撃側はまず数を合わせ、型は NULL を置いて避けにいきます。逆に言えば、この2つさえ揃えば、参照するテーブルは元と別で構いません。
列の数や型が合わずに返るエラーは、行き止まりではありません。何列で、どんな型なら通るのかを教えてくれる返事です。次の回では、このエラーを逆手にとって列の数を数えます。
縦に積むというのは、上の行と下の行を同じ表の続きとして並べることです。列の数や型が行ごとに違えば、そもそも1つの表になりません。データベースは中途半端に混ぜず、揃わなければ文ごと断ります。だから攻撃する側は、まず数と型を合わせにいきます。
直す方向と試し方
UNIONが刺さるのも、入力がSQLの構文へ食い込むからで、根は前回までと同じです。値を命令から切り離して渡せば、UNION と書いても文字列の一部にしかなりません。手を動かすなら、自分で用意した練習用のデータベースやSQLコンソールで、列の数や型を変えながらエラー文の違いを読みます。この章の演習はログインの穴が題材なのでUNIONは扱いません。試すのは自分が権限を持つ練習用の環境だけにします。