SQLインジェクション入門:仕組みと対策
UNIONで中身を運び出す
この回でやること
列数を数えたら、次は実際に中身を運び出します。文が通るように型を合わせ、画面に映る列を目印で探す一手を見ます。
- 読む 約 8 分
- 最後にクイズ 1 問
このレッスンで学ぶこと
中身を運び出すには、列の数を合わせるだけでなく、型を合わせることと、値が映る列を探すことの2つが要ります。この回はつないだSELECTの結果を実際に画面へ出すまでを、同じ users テーブルで見ます。
読み終えると、文が通ることと画面に映ることは別だと分かり、映る列を先に特定してから値を差し込めるようになります。
型が合わないと文ごと落ちる
UNIONは上下で列の型が揃わないと成り立たない、と基本の回で見ました。運び出すときも同じで、数値の列に文字列を差し込もうとすると、そこで文が落ちます。ただ、全部の列に狙った値を入れる必要はありません。映したい1列にだけ値を置き、残りは NULL で埋めます。NULL はどの型にも収まるので、型の衝突を避けられます。
SQL クエリ
SELECT name, role FROM users
WHERE name = 'tanaka'
UNION SELECT password, NULL FROM users --'どの列が画面に映るかを探す
文が通っても、その値が画面に出るとはかぎりません。検索結果の一覧が name の列だけを表示する作りなら、role の位置に置いた値は届いても表示されません。そこで、まず目印を流し込み、どの位置が画面に現れるかを確かめます。
SQL クエリ
SELECT name, role FROM users
WHERE name = 'no-such-name'
UNION SELECT 'AAA', 'BBB' --'存在しない名前で元の結果を空にし、AAAとBBBのどちらが画面に出るかを見ます。AAAが出れば1列目が映る列、BBBが出れば2列目です。映る列が分かったら、そこへ運び出したい値へ入れ替えます。
SQL クエリ
SELECT name, role FROM users
WHERE name = 'no-such-name'
UNION SELECT password, NULL FROM users --'これで users 全員のパスワードが、name のつもりの欄に一覧で並びます。列さえ合わせれば参照先は自由なので、同じ手で別のテーブルの中身も運び出せます。どんなテーブルがあるかは次回に調べます。
型さえ合えば文は通りますが、表示されない位置に値を置いても手元には返りません。だから先に目印で映る位置を1つ特定してから、そこへ狙った値を差し込みます。数を合わせただけで満足すると、通っているのに何も見えず手が止まります。
映らない列の型が数値だったとき、そこに文字列を置くと文ごと落ちるからです。映る1列に狙った値、残りは NULL と置けば、埋めた列の型を気にせず運び出せます。埋め草の NULL は表示されないので、じゃまにもなりません。
直す方向と、この講座で試せる範囲
刺さる根は前回までと同じで、入力がSQLの構文へ食い込むからです。値を命令から切り離して渡せば、UNION と書いても文字列の一部で終わります。この講座の演習で扱うのはログインの通り抜けまでで、UNIONを実際に走らせる口はありません。ここから先は考え方だけを押さえます。自分の手で確かめるなら、自分で用意した練習用のデータベースやSQLコンソールで、映る列やNULLの位置を変えながら返りを読みます。試すのは自分が権限を持つ練習用の環境だけにします。