SQLインジェクション入門:仕組みと対策
結果が画面に出ないとき
この回でやること
運び出した値が画面に映らなくても、真か偽かの差があれば中身は漏れます。1文字ずつ絞る考え方と、出力が無くても情報は漏れるという一点を見ます。
- 読む 約 9 分
- 最後にクイズ 1 問
このレッスンで学ぶこと
結果を画面に一切出さない作りでも、真か偽かで反応が変わるなら、中身は1文字ずつ漏れます。この回は値が返らなくても差だけを頼りに中身を絞る考え方を、同じ users テーブルで見ます。
読み終えると、漏らすのは画面に出る値ではなく真と偽の差だと分かり、出力を消しても守りにならない理由を説明できるようになります。
映らなくても、反応は残る
結果を画面に出さなくても、脆弱かを見分ける回で見たように、真の条件と偽の条件で反応が変わるなら手掛かりは残ります。ログインの 200 と 401、あるいは「見つかった」と「見つからない」の差が、1回につき「はい」か「いいえ」の1ビットを返します。値そのものは見えなくても、この1ビットは観測できます。
はい・いいえの質問に翻訳する
中身を直接は読めなくても、中身についての yes・no の質問なら投げられます。たとえば「admin のパスワードの1文字目は m より後ろか」を条件に混ぜ、真なら自分の行が返り、偽なら返らないように仕込みます。
プレーンテキスト
SELECT name, role FROM users
WHERE name = 'tanaka'
AND (admin の password の1文字目が 'm' より後ろ)括弧の中の真偽で、tanaka の行が返るか返らないかが変わります。返れば真、返らなければ偽。この1ビットが、質問の答えです。位置を1文字目、2文字目と動かし、文字ごとに問い直せば、映らないはずのパスワードが1文字ずつ形になります。
半分ずつ絞る
1文字を確かめるのに「a か。b か」と総当たりする必要はありません。列数を数えた回と同じで、「m より後ろか」で候補を半分に割り、次は残った半分をまた半分にと詰めます。文字の候補が数十でも、1文字あたり数回の質問で決まります。
情報を漏らすのは、画面に出る値ではありません。真と偽で何か1つでも変わる観測点です。反応が2通りに割れるなら、そこへ yes・no を無限に問えます。だから出力を消すことは対策になりません。見えないのに漏れている、が起こり得ます。
手数は多いですが、有限です。1文字あたり半分ずつ絞れば数回、それを文字数分だけ繰り返すだけです。人が手で打つ話ではなく、何千回でも機械が自動で送れます。遅いだけで、確実に終わります。
直す方向と、この講座で試せる範囲
根は前回までと同じで、値を命令から切り離して渡せば、括弧の中の条件はそもそも差し込めません。この講座の演習では、真偽で 200 と 401 が変わるところまでは見られますが、パスワードを1文字ずつ絞るには位置や文字を取り出す関数が要り、演習の評価器はそれを走らせません。ここから先は考え方だけを押さえます。手を動かすなら、自分で用意した練習用のデータベースで、真の条件と偽の条件を並べて反応の差を読みます。試すのは自分が権限を持つ練習用の環境だけにします。