SQLインジェクション入門:仕組みと対策
SQLの条件を書き換えて結果を変える
この回でやること
前回は穴の原因を見ました。今回は同じ穴で何ができるかを、閉じる・足す・消すの3手として手を動かしながら分解します。
- 読む 約 8 分
- 最後にクイズ 1 問
このレッスンで学ぶこと
条件式の書き換えは、閉じる・足す・消すという3つの操作の組み合わせでできています。この回は名前で探す1本のSQL(題材は同じ users テーブル)を、その3手に分解します。
読み終えると、手口の名前ではなく3つの操作の並べ替えとして、自分で組み立て直せるようになります。
元の問い合わせ
利用者を名前で探す画面があり、内部ではこのSQLが組み立てられます。
SQL クエリ
SELECT name, role FROM users WHERE name = 'tanaka'tanaka の部分が入力欄から来ます。普通の名前を入れれば、その1人分だけが返ります。攻撃はこの1行を「全行」に変えることから始まります。
手その1 文字列を閉じる
入力の先頭にシングルクォートを1つ置くと、テンプレートが開いていた文字列がそこで閉じます。tanaka' と入れると、データベースは name の値を tanaka までと読み、その後ろを値ではなく命令として読み始めます。まだ何も足していません。値の枠から抜け出しただけです。
手その2 常に真になる条件を足す
枠から抜けたら、真偽が決まる条件を継ぎ足せます。OR 1=1 は左も右も同じなので、どの行でも真です。OR は「どちらかが真なら真」なので、元の name = 'tanaka' が偽の行まで巻き込み、全行が条件を満たします。
SQL クエリ
SELECT name, role FROM users WHERE name = 'tanaka' OR 1=1ただし組み上がった文は末尾に問題を抱えています。テンプレートには閉じ引用符が1つ残っていて、そのままでは引用符の数が合わず構文エラーになります。
手その3 残りを消す
末尾に -- を置くと、そこから行末までがコメントになり、データベースは読みません。残っていた閉じ引用符も、後ろに続く並び替えや別の条件も、まとめて消えます。入力を tanaka' OR 1=1 -- にすると、こう組み上がります。
SQL クエリ
SELECT name, role FROM users WHERE name = 'tanaka' OR 1=1 --'末尾の ' はもうコメントの中なので、帳尻を合わせる手間が要りません。全行が返ります。
全行を返しているのは OR 1=1 の働きで、-- は後始末です。この2つを混同すると、末尾さえ付ければ通ると誤解し、条件を足し忘れたまま手が止まります。役割を分けて覚えます。
要りません。末尾に何も続かない単純な文なら -- は省けますし、tanaka' OR '1'='1 のように条件側の引用符で帳尻を合わせる手もあります。3手は「必ず全部使う型」ではなく、状況で選ぶ部品です。閉じて、足して、必要なら消す。手口にどんな名前が付いても、中身はこの組み合わせです。
直す方向と試し方
弾く文字を増やす対策では追いつきません。効くのは値を命令の組み立てから切り離すことで、その具体は後の回で扱います。自分の手で確かめるなら、練習用の環境で入力を少しずつ変え、返る行数の動きを見ます。tanaka だけなら1行、tanaka' OR 1=1 -- なら全行、という差がそのまま3手の効き目です。試すときは自分が権限を持つ練習用の環境だけで行い、他人のサイトへ送ってはいけません。