Gemini 先生にSC試験(ブラインドSQLインジェクション)の解説をしてもらっていました。備忘として残しておきます。
もし、どこかのコンテンツをGeminiが学習してそのまま回答しているように見受けられる場合は教えてください。この記事は削除させて頂きます。
情報処理安全確保支援士 R7 春期 午後 問2 設問1の解説です。
以下がプロンプトです。
〈問題文中より前提条件〉
とあるWebのキャンペーンサイトで脆弱性診断ツールを使用して診断したところ、SQLインジェクションの脆弱性が見つかりました。
キャンペーン情報はDBに保存されており、キャンペーンページのURLのクエリパラメータにコンテンツ番号が含まれています。
例:https://site-x.m-sha.co.jp/info?article=20250101
コンテンツ番号がDBサーバに存在しない場合、又はSQLが構文エラーになる場合は、"コンテンツがありません"というメッセージを返します。
また、Webアプリプログラムにおいて、クエリパラメータ article の値はSQLでの検索は数値型として扱われます。
上記仕様のサイトで診断ツールのパラメータは以下が指定されました。問題はこれらのクエリパラメータの応答を回答するものです。
①article=20250401
②article=20250401'
③article=20250401' %20and%20' a'=' a
④article=20250401' %20and%20' a'=' b
⑤article=20250401' %20and%201=0
⑥article=20250401' %20and%201=1
答えは①が2025年4月1日のキャンペーンのコンテンツが表示される。
②〜⑤がコンテンツがありませんが表示される。
⑥が2025年4月1日のキャンペーンのコンテンツが表示される。
以下が解説です。
脆弱性の原因となるSQL文の想定
まず、この問題の背景にあるWebアプリケーションの脆弱性を理解するため、どのようなSQL文が実行されているかを想定します。
Webアプリのプログラムは、URLのクエリパラメータarticleの値を使ってデータベースから情報を取得します。articleの値は数値型として扱われるため、例えばarticle=20250401というリクエストがあった場合、内部では以下のようなSQL文が実行されていると推測できます。
SELECT * FROM campaign_table WHERE article_id = 20250401;
脆弱性があるということは、このarticleパラメータの値が適切にサニタイズ(無害化)されずに、SQL文に直接埋め込まれていることを意味します。そのため、攻撃者はこのパラメータに特別な文字列(ペイロード)を挿入することで、SQL文の構造を意図的に変更できます。
各クエリパラメータの応答の解説
では、ご提示いただいた各クエリパラメータがどのようにSQL文を変化させ、どのような結果をもたらすのかを順に見ていきましょう。
① article=20250401
* 生成されるSQL文の想定:
SELECT * FROM campaign_table WHERE article_id = 20250401;
* 解説:
この値は正しい数値形式であり、SQL文の構文は崩れません。データベースにarticle_idが20250401のレコードが存在すれば、そのコンテンツが正常に表示されます。
② article=20250401'
* 生成されるSQL文の想定:
SELECT * FROM campaign_table WHERE article_id = 20250401';
* 解説:
20250401の後にシングルクォーテーション(')が付いています。これにより、SQL文の構文が不正になります。問題文の前提条件「SQLが構文エラーになる場合は、"コンテンツがありません"というメッセージを返す」に該当するため、このメッセージが表示されます。
③ article=20250401' %20and%20'a'='a
* 生成されるSQL文の想定:
URLエンコードされている%20はスペースに、%27はシングルクォーテーションに変換されます。
SELECT * FROM campaign_table WHERE article_id = 20250401' and 'a'='a';
* 解説:
20250401'の後に'a'='a'という条件式が続いています。しかし、ここでも20250401の後にシングルクォーテーションが来ているため、SQL文はWHERE article_id = 20250401'という形で構文エラーとなります。その後の条件式は実行されません。よって、"コンテンツがありません"というメッセージが表示されます。
④ article=20250401' %20and%20'a'='b
* 生成されるSQL文の想定:
SELECT * FROM campaign_table WHERE article_id = 20250401' and 'a'='b';
* 解説:
これも③と同様に、20250401の後のシングルクォーテーションで構文エラーとなります。その後の'a'='b'は評価されません。したがって、"コンテンツがありません"と表示されます。
⑤ article=20250401' %20and%201=0
* 生成されるSQL文の想定:
SELECT * FROM campaign_table WHERE article_id = 20250401' and 1=0;
* 解説:
これも②~④と同じ理由で、20250401'の時点で構文エラーとなり、"コンテンツがありません"と表示されます。
⑥ article=20250401' %20and%201=1
* 生成されるSQL文の想定:
SELECT * FROM campaign_table WHERE article_id = 20250401' and 1=1;
* 解説:
これも②~⑤と同じように見えますが、実はここには巧妙な罠が隠されています。問題文の前提条件「クエリパラメータ article の値はSQLでの検索は数値型として扱われます」が重要です。
多くのデータベースシステムでは、文字列を数値型として扱う際に、先頭の数値だけを解釈し、その後の非数値文字(この場合は')を無視して変換しようとします。
この場合、20250401'という文字列は20250401という数値に変換されます。その結果、SQL文はWHERE article_id = 20250401として実行され、and 1=1という常に真となる条件式が追加されます。
最終的に実行されるSQL文は以下のような論理式となります。
SELECT * FROM campaign_table WHERE article_id = 20250401 AND 1=1;
これはSELECT * FROM campaign_table WHERE article_id = 20250401;と論理的に同等です。したがって、コンテンツが存在すれば正常に表示されます。これは、ブラインドSQLインジェクションと呼ばれる手法の一種で、真偽の判断(1=1や1=0など)によって、脆弱性の存在や情報を引き出すことが可能になることを示しています。
まとめ
この問題は、単にSQL文がどう変化するかだけでなく、Webアプリケーションがパラメータの値をどのように解釈し、データベースがその値をどう処理するかという前提条件を正確に読み解くことが鍵となります。
特に⑥のケースは、「数値型として扱われる」という仕様が、脆弱性診断において予期せぬ挙動を引き起こす可能性があることを示唆しており、非常に実践的な内容です。
セキュリティの勉強、頑張ってください。この解説がお役に立てば幸いです。
%27はどこから出てきたのか謎です。
なお、文中にブラインドSQLインジェクションの成立が示唆されたと言及されているので、それについても解説してもらいました。
はい、この文章題の文脈において、先ほどの攻撃と同じ手法でDBのテーブル名を特定できる手法について解説します。これはブラインドSQLインジェクションの応用であり、推測と検証を繰り返すことで情報を引き出す方法です。
ブラインドSQLインジェクションによるテーブル名特定
この攻撃は、以下の流れでデータベースのテーブル名を特定します。
* 推測: 攻撃者は一般的なテーブル名(例:users、accounts、campaignsなど)や、そのデータベースにありそうなテーブル名の文字を一つずつ推測します。
* 検証: 推測したテーブル名が正しいかを、SQLクエリに**AND演算子とEXISTS句**を組み合わせて検証します。
* EXISTS (SELECT * FROM 推測したテーブル名)という式は、指定したテーブルが存在すればTRUE、存在しなければFALSEを返します。
* これを、先ほどのAND 1=1と同様に、元のSQLクエリに組み込みます。
具体的な攻撃クエリの例
問題の例に当てはめて解説します。攻撃者は、campaign_tableというテーブル名が存在するかを検証したいとします。
* 攻撃クエリ: article=20250401' AND EXISTS(SELECT * FROM campaign_table) --
* --はSQLのコメントアウト記号で、その後のクエリを無効化します。これにより、元のクエリが意図せず壊れるのを防ぎます。
* 生成されるSQL文の想定:
SELECT * FROM campaign_table WHERE article_id = 20250401 AND EXISTS(SELECT * FROM campaign_table) --'
* 応答の検証:
* もし**campaign_tableが存在すれば**、EXISTS句がTRUEを返し、クエリ全体がTRUEとなります。結果として、元のコンテンツ(2025年4月1日のキャンペーン)が正常に表示されます。
* もし**campaign_tableが存在しなければ**、EXISTS句がFALSEを返し、クエリ全体がFALSEとなります。結果として、コンテンツは表示されず、「コンテンツがありません」というメッセージが返されます。
攻撃者はこの応答の違いを利用して、campaignという文字から始まり、_、t、a...と一文字ずつ推測と検証を繰り返し、正しいテーブル名を特定していきます。
なぜこの攻撃が成功するのか
この攻撃が成功するのは、元のアプリケーションがユーザー入力を適切にサニタイズ(無害化)していないためです。これにより、攻撃者は悪意のあるSQL文を挿入し、アプリケーションの応答の違い(コンテンツが表示されるか、エラーになるか)から、データベースの情報を推測できるのです。これは、攻撃者がデータベースから直接情報を取得するのではなく、アプリケーションの挙動を通じて間接的に情報を得ているため、「ブラインド(盲目的な)」インジェクションと呼ばれます。
要するにANDとEXISTS句を使って、テーブル名が存在するかどうかを検証することができるそうです。
ANDの前のSQL文は正規のSQL分なので、必ず真になるはずで、ANDで繋いだ後ろのEXISTS句に検証したいテーブル名に対するSELECT文を挿入すると、テーブルが存在していれば真が返ってきて、AND全体としては成立し、正規の動作をすることで、テーブルが存在していたことがわかるということですね。
逆にテーブルが存在しない場合、AND演算子は偽を返すので、"コンテンツがありません。"となるわけです。
お陰様で、ブラインドインジェクションの脆弱性と対策についてよくわかりました。