コンテンツにスキップ

6-2. 演習問題


1-1. OWASP Top 10 の主な役割として最も適切なのはどれか。

  • A. 重要な Web アプリケーションリスクを整理し、開発者の注意点を共有すること
  • B. Git のブランチ名を統一すること
  • C. データベースの正規化だけを評価すること
解答と解説

正解:A. 重要な Web アプリケーションリスクを整理し、開発者の注意点を共有すること

  • A が正しい。OWASP Top 10 は、重要なセキュリティリスクを整理した代表的な啓発資料である。
  • B は誤り。ブランチ運用のルールではない。
  • C は誤り。データベース設計専用の資料ではない。

OWASP Top 10 の価値は、設計・実装・レビュー・テストの各場面で「何を疑うべきか」を共有できる点にある。

1-2. 現行の OWASP Top 10:2025 で SQL InjectionXSS が主に含まれるカテゴリとして最も適切なのはどれか。

  • A. A05: Injection
  • B. A02: Security Misconfiguration
  • C. A09: Security Logging & Alerting Failures
解答と解説

正解:A. A05: Injection

  • A が正しい。現行の 2025 版では、SQLi と XSS は主に Injection のカテゴリで捉えられる。
  • B は誤り。設定不備の話ではない。
  • C は誤り。ログや通知の不備とも別問題である。

SQLi と XSS は見た目は違うが、どちらも「入力が構文や命令として解釈される」という共通点を持つ。

1-3. 現行の OWASP Top 10:2025 における CSRF の扱いとして最も適切なのはどれか。

  • A. 現在も単独の Top 10 項目である
  • B. Broken Access Control に含まれる関連リスクとして扱われる
  • C. もう対策不要なので一覧から外れた
解答と解説

正解:B. Broken Access Control に含まれる関連リスクとして扱われる

  • B が正しい。現行の 2025 版では、CSRF は単独項目ではなく Broken Access Control の文脈で扱われる。
  • A は誤り。古い資料の印象をそのまま引きずっている。
  • C は誤り。単独項目でないことと、重要でないことは別である。

現在の OWASP Top 10 は、攻撃名そのものよりも、より根本原因に近いカテゴリで整理する傾向が強い。

1-4. SQL Injection への対策として最も適切なのはどれか。

  • A. パラメータ化クエリを使い、データとクエリ構造を分離する
  • B. 入力を文字列連結したあとで見た目だけ確認する
  • C. クライアント側の入力チェックだけに任せる
解答と解説

正解:A. パラメータ化クエリを使い、データとクエリ構造を分離する

  • A が正しい。SQLi の本質的な対策は、データと SQL 構造を分けることにある。
  • B は誤り。見た目を確認しても、危険な結合方法そのものは残る。
  • C は誤り。クライアント側の検証は攻撃者に回避されうる。

「入力をどう制限するか」より前に、「危険な結合方法をしない」ことが重要である。

1-5. XSS を防ぐ表示方法として最も適切なのはどれか。

  • A. 信頼できない入力をそのまま innerHTML へ入れる
  • B. 出力エンコーディングや textContent のような安全な API を使う
  • C. ログイン済みユーザーの入力なら無条件で表示する
解答と解説

正解:B. 出力エンコーディングや textContent のような安全な API を使う

  • B が正しい。XSS の対策では、出力文脈に応じて無害化し、安全な API を使うことが重要である。
  • A は誤り。innerHTML へ無警戒に渡すと、HTML として解釈される危険がある。
  • C は誤り。ログイン済みユーザー入力でも危険な内容は入りうる。

入力元を過信するのではなく、出力時の扱いを安全にする発想が必要である。

1-6. Broken Access Control の例として最も適切なのはどれか。

  • A. URL の bookId を変えたら他人の本の編集画面が開けた
  • B. 画像が少しぼやけて表示された
  • C. ダークモードの設定が保存されなかった
解答と解説

正解:A. URL の bookId を変えたら他人の本の編集画面が開けた

  • A が正しい。これは権限外の閲覧や操作を許しており、Broken Access Control の典型例である。
  • B は誤り。表示品質の問題であり、セキュリティカテゴリではない。
  • C は誤り。設定保存の不具合であり、直接の権限制御問題ではない。

「自分が見てよいものだけ見える」「自分がしてよい操作だけできる」が守られているかが access control の要点である。


次の文章の空欄を埋めてください。

  1. OWASP Top 10 で、SQLi や XSS が主に含まれるカテゴリを (   ) という。
  2. 権限外の操作や閲覧を許してしまうカテゴリを (   ) という。
  3. SQL の構造とデータを分ける代表的な対策を (   ) クエリという。
  4. XSS 対策として、表示文脈に応じて文字を無害化する考え方を (   ) という。
  5. CSRF への代表的な対策の 1 つは、状態変更リクエストに (   ) を付けて正当性を確認する方法である。
  6. OWASP Top 10 は、10 個だけ覚えれば終わりの完全な (   ) ではない。
解答欄
解答と解説
  1. Injection

    SQLi や XSS など、入力が構文や命令として解釈される問題群をまとめるカテゴリである。

  2. Broken Access Control

    権限外の閲覧や更新、管理機能への侵入などを許してしまう問題群である。

  3. パラメータ化

    SQL の構造と値を分離し、入力がクエリの一部として解釈されにくくする基本対策である。

  4. 出力エンコーディング

    表示先に応じて危険な文字を無害化し、ブラウザに命令として解釈させにくくする考え方である。

  5. トークン

    フォームやリクエストごとにトークンを埋め込み、状態変更リクエストが本当に正当な画面から送られたものかを確かめる代表的な仕組みである。

  6. チェックリスト

    OWASP Top 10 は参考になるが、10 項目だけ見れば終わり、という完全な表ではない。


3-1. なぜ OWASP Top 10 を「攻撃名の暗記表」としてではなく、「根本原因を考える資料」として使うべきなのか説明してください。

解答欄
解答と解説

個別の攻撃名だけを暗記しても、なぜ起きるのかや、どう再発防止するかが見えにくいからである。 たとえば「外部入力をそのまま混ぜる」という同じ根本原因が、SQLi や XSS など複数の問題を生む。 そのため、OWASP Top 10 は「どんな名前の攻撃があるか」より、「どんな設計や実装が危険か」を考えるために使うべきである。

3-2. SQL Injection と XSS の共通点と違いを説明してください。

解答欄
解答と解説

共通点は、どちらも信頼できない入力が、解釈器に命令や構文として扱われることにある。 SQLi ではデータベースが SQL を解釈し、XSS ではブラウザが HTML / JavaScript を解釈する。 つまり本質は同じ Injection だが、攻撃される対象の解釈器と影響の出方が違う。

3-3. CSRF が、ログイン済みのブラウザを使う Web アプリで起こりやすい理由を説明してください。

解答欄
解答と解説

ブラウザは正規サイトへログインしていると、Cookie などの認証情報を自動で送ることがある。 その状態で悪意あるページから状態変更リクエストを誘発されると、サーバーは本人の正当な操作と誤認しやすい。 そのため、ログイン済みであること自体が CSRF 悪用の前提になりうる。

3-4. なぜログやアラート、例外時の安全な停止もセキュリティの一部なのか説明してください。

解答欄
解答と解説

攻撃や異常は、起きること自体をゼロにできない場合があるため、発見と影響抑制の仕組みが必要になる。 ログやアラートが弱いと侵害に気づけず、異常時の処理が危険だと情報漏えいや権限逸脱が起こりやすい。 そのため、セキュリティは「侵入を防ぐ」だけでなく、「異常時に安全側へ倒れ、気づけるようにする」ことまで含む。


安全側のTODOを実装し、危険な実装との出力の違いを確認せよ。SQLite のプレイグラウンドでも同様に攻撃文字列の影響を観察する。

  1. buildSafeSearchQuery でSQL文と値を分離した { sql, params } オブジェクトを返す
  2. verifyCsrforiginsessionToken === requestToken の両方を確認して true/false を返す
  3. 実装後に実行し、unsafe(危険)と safe(安全)の出力の違いを確認する
実行プレイグラウンド
編集内容は自動保存されます / Ctrl+Enter でも実行できます
出力
「実行」を押すと、ここに結果が表示されます。
  • unsafe query では攻撃文字列がSQL本文に混入し、safe query では値として分離されること
  • unsafe html にはタグが残り、safe html ではエンコードされること
  • csrf accepted (evil origin)falsecsrf accepted (valid)true になること

⑥ SQLite で危険な検索結果を確認する

次は SQLite 上で、同じ攻撃文字列が「SQL の一部になった場合」と「値として扱われた場合」で結果がどう変わるかを見ます。 まずは危険な文字列連結で出来上がった SQL を実行する。

SQLプレイグラウンド
ブラウザ内の SQLite で実行します / SQL は自動保存されます / Ctrl+Enter でも実行できます
結果
「実行」を押すと、ここに実行結果が表示されます。

次の SQL が実行できれば成功:

SELECT id, title
FROM books
WHERE title = '' OR '1'='1'
ORDER BY id;

結果は次のようになれば成功:

+----+------------------+
| id | title |
+----+------------------+
| 1 | Git |
| 2 | JavaScript入門 |
| 3 | Network設計 |
+----+------------------+

攻撃文字列により、WHERE 条件が常に真になり、全件が返ってしまうことを確認する。

⑦ SQLite で対策クエリの結果を確認する

次は、同じ攻撃文字列 ' OR '1'='1 を、プレースホルダ ?値として渡す対策クエリを実行する。 この下のプレイグラウンドでは、? へ固定でその文字列が渡される。

SQLプレイグラウンド
ブラウザ内の SQLite で実行します / SQL は自動保存されます / Ctrl+Enter でも実行できます
結果
「実行」を押すと、ここに実行結果が表示されます。

次の SQL が実行できれば成功:

SELECT id, title
FROM books
WHERE title = ?
ORDER BY id;

結果欄に 0 行でした。 と表示されれば成功:

  • 同じ攻撃文字列でも、SQL の構造ではなく「本のタイトルの値」として扱われる
  • その文字列と一致するタイトルは存在しないため、全件取得にはならない

⑧ プレースホルダへ渡った値そのものも確認する

対策クエリ側の SQL を次のように書き換えて、もう一度実行する。

SELECT ? AS attack_input;

結果は次のようになれば成功:

+----------------+
| attack_input |
+----------------+
| ' OR '1'='1 |
+----------------+

つまり、対策クエリでは攻撃文字列が「命令」ではなく、1つの値として扱われていると分かる。

実務では、この考え方を手書きエスケープではなく、プレースホルダ付きのパラメータ化クエリで実現する。

解答と解説

② そのまま実行したときの見方

unsafe query SELECT * FROM books WHERE title = '' OR '1'='1'
safe query {"sql":"SELECT * FROM books WHERE title = ?","params":["' OR '1'='1"]}
unsafe html <p><img src=x onerror="alert(1)"></p>
safe html <p>&lt;img src=x onerror=&quot;alert(1)&quot;&gt;</p>
csrf request accepted false

unsafe query では、攻撃文字列が SQL 本文へ直接入り込んでいる。 一方 safe query では、SQL の構造は固定で、値が別の params として扱われている。 unsafe html はタグをそのまま含むが、safe html<" がエスケープされ、文字列として表示される前提になっている。 csrf request accepted false は、送信元やトークンが正しくなければ状態変更を受け付けない、という考え方を表している。


③ 普通の検索語に変えたとき

unsafe query SELECT * FROM books WHERE title = 'JavaScript入門'
safe query {"sql":"SELECT * FROM books WHERE title = ?","params":["JavaScript入門"]}

普通の値に見えても、危険なのは「攻撃文字列かどうか」だけではなく、「文字列連結で構造へ混ぜる書き方」である。 つまり脆弱性は入力値だけでなく、実装パターンにある。


④ コメント表示を変えたとき

unsafe html <p>Hello <b>team</b></p>
safe html <p>Hello &lt;b&gt;team&lt;/b&gt;</p>

unsafe html<b> をタグとして扱える形のまま残している。 safe html はタグを文字列へ変えているため、ブラウザが構文として解釈しにくい。 XSS 対策では、危険な入力を「見えないようにする」のではなく、「構文として扱わせない」ことが重要である。


⑤ CSRF 検証を通したとき

csrf request accepted true

この結果は、送信元とトークンの両方が正当であるときだけリクエストを通す、という考え方を示している。 実際のフレームワークでは、CSRF トークン、SameSite Cookie、Origin / Referer 確認などを組み合わせることが多い。 重要なのは「ログイン済みだから許可」ではなく、「その操作が正当な画面から来たものか」を追加確認することである。


⑥-⑧ SQLite で SQL Injection の結果差を確認したとき

危険な連結結果では、次の SQL がそのまま実行される。

SELECT id, title
FROM books
WHERE title = '' OR '1'='1'
ORDER BY id;

この WHERE 条件は実質的に常に真になるため、全件が返ってしまう。 つまり攻撃文字列が「タイトルの値」ではなく、SQL の条件そのものへ入り込んでいる。

一方、対策クエリでは次の SQL を使う。

SELECT id, title
FROM books
WHERE title = ?
ORDER BY id;

ここで ? へ渡されるのは ' OR '1'='1 という 1 つの文字列値である。 そのため SQLite は、それを条件式として実行するのではなく、「そのタイトルと等しい行を探す」だけになる。 一致するタイトルがなければ 0 行でした。 となり、全件取得にはならない。

さらに SELECT ? AS attack_input; を実行すると、攻撃文字列がそのまま 1 つの値として返る。 これが、危険な連結とパラメータ化クエリの決定的な違いである。


図で見る

SQLi: 入力が SQL の一部になる
XSS : 入力が HTML / JS の一部になる
CSRF: ログイン済みブラウザが意図せずリクエストを送る

3つとも有名な名前だが、見るべき点は「どこで境界が崩れたか」である。