SQLインジェクション入門:仕組みと対策
脆弱かどうかを見分ける
この回でやること
ある入力欄がSQLに届いているかを、壊さずに確かめます。シングルクォート1つで反応が変わるか、真と偽で結果が変わるかを読む方法です。
- 読む 約 9 分
- 最後にクイズ 1 問
このレッスンで学ぶこと
脆弱かどうかの見分けは、入力欄を壊すことではなく、返ってくる反応の差を読むことで進めます。この回はシングルクォートを1つ入れて反応が変わるか、真と偽で結果が変わるかを、自分のアカウント tanaka だけで確かめます。
読み終えるころには、エラーの有無ではなく反応が変わったかどうかで、届いているかを見分けられるようになります。
まず、普通の反応を知る
見分けは、普通の反応との比較から始まります。基準がなければ、差にも気づけません。自分のアカウントで正しくログインすれば200が返り、パスワードを間違えればinvalid credentialsという401が返ります。この2つが、正常なときの反応です。
シングルクォートを1つ、そっと入れる
次に、パスワードの末尾にシングルクォートを1つだけ足してみます。正しいパスワードのうしろに'が付いた状態です。すると応答が500に変わり、SQL syntax errorが返ります。応答に含まれるquery欄を見ると、組み上がったSQLはこうなっています。
SQL クエリ
SELECT name, role FROM users WHERE name = 'tanaka' AND password = 'tanaka-pass''閉じたはずの文字列のあとにクォートが1つ余り、構文が壊れています。普段は401で返っていた欄が、500のSQLエラーに変わった。この反応の変化こそが、入力した文字が値ではなく構文としてSQLに届いている証拠です。
エラーが出たこと自体は、まだ「届いているらしい」までです。そして何も起きなくても安全とはかぎりません。画面にエラーを出さない作りもあり、その場合は反応の差がもっと静かな形で現れます。大事なのはエラーの有無ではなく、反応が変わったかどうかです。
真と偽で、結果が変わるかを見る
届いていそうだと分かったら、次は論理を動かせるかを確かめます。同じく自分のパスワードのうしろに、今度は条件を足します。tanaka-pass' AND '1'='1と入れれば200のまま通り、tanaka-pass' AND '1'='2に変えると401に落ちます。
SQL クエリ
SELECT name, role FROM users
WHERE name = 'tanaka'
AND password = 'tanaka-pass' AND '1'='1'パスワードは正しいまま、足した条件の最後の1文字だけが違います。それで結果が真と偽に分かれる。この差は、データベースが足した条件を評価している、つまり論理をこちらから動かせることを意味します。
見分けの根拠は「エラーが出た」ではなく「反応が変わった」ことです。普通の入力と探りで応答が変わる、真の条件と偽の条件で結果が変わる。逆に、真と偽で同じ反応しか返らない欄は、そこでは届いていない可能性が高いと読みます。
手を動かすときは、必ず自分が権限を持つ練習用の環境だけで行ってください。他人のサイトで確かめてはいけません。やっているのは壊すことではなく、正常な反応と探りの反応を並べて差を読むことです。届いていて、論理も動かせると分かってはじめて、前回のadmin' --のような手が意味を持ちます。