情報処理安全確保支援士 2023年 秋期 午後 問01
Webアプリケーションプログラムの開発に関する次の記述を読んで、設問に答えよ。
Q社は、洋服のEC事業を手掛ける従業員100名の会社である。WebアプリQというWebアプリケーションプログラムでECサイトを運営している。ECサイトのドメイン名は“□□□.co.jp”であり、利用者はWebアプリQにHTTPSでアクセスする。WebアプリQの開発と運用は、Q社開発部が行っている。今回、WebアプリQに、ECサイトの会員による商品レビュー機能を追加した。図1は、WebアプリQの主な機能である。


ある日、会員から、無地Tシャツのレビューページ(以下、ページVという)に16件表示されるはずのレビューが2件しか表示されていないという問合せが寄せられた。開発部のリーダーであるNさんがページVを閲覧してみると、画面遷移上おかしな点はなく、図2が表示された。

WebアプリQのレビューページでは、次の項目がレビューの件数分表示されるはずである。
・レビューを投稿した会員のアイコン画像
・レビューを投稿した会員の表示名
・レビューが投稿された日付
・レビュー評価(1~5個の★)
・会員が入力したレビュータイトル
・会員が入力したレビュー詳細
不審に思ったNさんはページVのHTMLを確認した。図3は、ページVのHTMLである。
↩設問2
↩設問2 図3のHTMLを確認したNさんは、会員Aによって15件のレビューが投稿されていること、及びページVには長いスクリプトが埋め込まれていることに気付いた。Nさんは、ページVにアクセスしたときに生じる影響を調査するために、アクセスしたときにWebブラウザで実行されるスクリプトを抽出した。図4は、Nさんが抽出したスクリプトである。
Nさんは、会員Aの投稿はクロスサイトスクリプティング(XSS)脆弱性を悪用した攻撃を成立させるためのものであるという疑いをもった。NさんがWebアプリQを調べたところ、WebアプリQには、会員が入力したスクリプトが実行されてしまう脆弱性があることを確認した。加えて、WebアプリQがcookieにHttpOnly属性を付与していないこと及びアップロードされた画像ファイルの形式をチェックしていないことも確認した。
Q社は、必要な対策を施し、会員への必要な対応も行った。
設問1:この攻撃で使われたXSS脆弱性について答えよ。
問題文を見る(1)XSS脆弱性の種類を解答群の中から選び、記号で答えよ。
解答群
ア:DOM Based XSS
イ:格納型XSS
ウ:反射型XSS
模範解答
イ
解説
解答の論理構成
- まず攻撃コードがどこに置かれているかを確認します。問題文には
「“ページVには長いスクリプトが埋め込まれている”」
「“会員Aによって15件のレビューが投稿されている”」
とあり、悪意あるJavaScriptがレビュー本文としてサーバ側に保存されていることが分かります。 - 保存されたレビューは、ページVを閲覧したすべての利用者のブラウザに配信され、そこで実行されます。これは問題文の
「“アクセスしたときにWebブラウザで実行されるスクリプトを抽出した”」
から明らかです。実際、図4のスクリプトは閲覧者のクッキーを含むファイルをアップロードする処理を行っています。 - 以上より、攻撃コードは
・サーバに“格納”され
・第三者のリクエストに“反射”されるのではなくそのまま配信され
・結果として閲覧者側で自動実行される
という流れです。 - この性質は、一般にStored/Persistent XSSと呼ばれるものであり、解答群で該当するのは「イ:格納型XSS」です。
誤りやすいポイント
- URLパラメータや検索結果が関わるとreflexiveと即断してしまうが、本問ではレビューという恒常的なデータ領域が利用されている点を見落としやすいです。
- DOMBasedと混同しやすいですが、DOMBasedはクライアント側のJavaScriptがlocation.hashなどを直接解析してスクリプトを生成するケースです。本問ではサーバから送られたHTMLに既にスクリプトが含まれており該当しません。
- 「閲覧をトリガに実行される=反射型」と誤認するケースがあります。実行タイミングではなく“保管場所”と“配信方法”に着目することが重要です。
FAQ
Q: 投稿した本人だけでなく他の会員にも実行されるのはなぜですか?
A: レビューはサーバのデータベースに保存され、そのままHTMLとして再配信されるため、ページVを開いた全ユーザのブラウザでスクリプトが動きます。
A: レビューはサーバのデータベースに保存され、そのままHTMLとして再配信されるため、ページVを開いた全ユーザのブラウザでスクリプトが動きます。
Q: HttpOnly属性が無い点はXSSの種類判定に関係しますか?
A: 判定そのものには関係しません。HttpOnlyの欠如はクッキー窃取を容易にする“被害拡大要因”であり、脆弱性の分類(格納型・反射型・DOMBased)には影響しません。
A: 判定そのものには関係しません。HttpOnlyの欠如はクッキー窃取を容易にする“被害拡大要因”であり、脆弱性の分類(格納型・反射型・DOMBased)には影響しません。
Q: 図4がXMLHttpRequestを使っているのは珍しいのですか?
A: 手口としては典型的です。格納型XSSでスクリプトを仕込み、XHRでdocument.cookieを含むファイルをアップロードすることでセッション固定や乗っ取りを狙う例は古くから報告されています。
A: 手口としては典型的です。格納型XSSでスクリプトを仕込み、XHRでdocument.cookieを含むファイルをアップロードすることでセッション固定や乗っ取りを狙う例は古くから報告されています。
関連キーワード: XSS, cookie, XMLHttpRequest, FormData, セッションID
設問1:この攻撃で使われたXSS脆弱性について答えよ。
問題文を見る(2)WebアプリQにおける対策を、30字以内で答えよ。
模範解答
レビュータイトルを出力する前にエスケープ処理を施す。
解説
解答の論理構成
- 攻撃の原因
- 【問題文】では「WebアプリQには、会員が入力したスクリプトが実行されてしまう脆弱性がある」と明示しています。
- 図3のHTML断片には Good<script>…</script>がそのまま出力されており、会員が自由記述できる「レビュータイトル」に <script> タグが混入していることが分かります。
- 脆弱性の種類
- 「クロスサイトスクリプティング(XSS)脆弱性」を悪用され、ブラウザが攻撃者のスクリプトを実行しています。
- 発生箇所の特定
- 攻撃コードは「レビュータイトル」フィールド経由で埋め込まれたため、出力時に無加工でHTMLに挿入される設計が問題です。
- 求められる対策
- 入力値を保存する際ではなく、「レビュータイトルを出力する前」にHTMLエスケープを行えば、< や > が文字列として表示され、スクリプトは実行されません。
- したがって模範解答「レビュータイトルを出力する前にエスケープ処理を施す。」となります。
誤りやすいポイント
- 入力値検証だけで十分と誤解し、「出力時エスケープ」の重要性を見落とす。
- JavaScriptのinnerText代入など、実装手段を答えてしまい設問の趣旨から逸脱。
- HttpOnly属性の設定や画像形式チェックを対策と勘違いし、本設問の焦点(XSS対策)から外れる。
FAQ
Q: なぜ保存時のフィルタリングではなく出力時エスケープを強調しているのですか?
A: 保存時に正規化すると、表示場所ごとに必要なサニタイズ方法が異なり破綻しやすいからです。出力時なら位置に合わせた適切なエスケープを確実に適用できます。
A: 保存時に正規化すると、表示場所ごとに必要なサニタイズ方法が異なり破綻しやすいからです。出力時なら位置に合わせた適切なエスケープを確実に適用できます。
Q: Content-Security-Policyを設定すれば十分ですか?
A: CSPは強力な追加防御ですが、根本的な対策はユーザ入力を無害化してHTMLに出力することです。本問の要求はまずエスケープ処理です。
A: CSPは強力な追加防御ですが、根本的な対策はユーザ入力を無害化してHTMLに出力することです。本問の要求はまずエスケープ処理です。
Q: DOMPurifyなどのライブラリ使用でも良いですか?
A: はい。ライブラリであっても「レビュータイトルを出力する前にエスケープ処理を施す」という方針を満たせば適切と判断されます。
A: はい。ライブラリであっても「レビュータイトルを出力する前にエスケープ処理を施す」という方針を満たせば適切と判断されます。
関連キーワード: XSS, エスケープ、DOM, Cookie, セッションID
設問2:
問題文を見る図3について、入力文字数制限を超える長さのスクリプトが実行されるようにした方法を、50字以内で答えよ。
模範解答
HTMLがコメントアウトされ一つのスクリプトになるような投稿を複数回に分けて行った。
解説
解答の論理構成
- 攻撃者である「会員A」は、同じ商品に「15件」のレビューを投稿している(図3より判明)。
- 各レビューの「レビュータイトル」に <script> の開始タグを分割して記述し、途中に /* と */ を交互に配置している。これによりブラウザがコメントとして無視する領域とスクリプトとして解釈する領域を自在に切り替えられる。
- WebアプリQには「会員が入力したスクリプトが実行されてしまう脆弱性」があるため、HTMLエスケープが行われず、投稿内容がそのままページに埋め込まれる。
- レビューは一覧表示時に連続して並ぶため、コメントアウトで“つなげた”各レビュータイトルの内容がブラウザ上では1本の <script> として結合され、長大なスクリプト(図4参照)が完成・実行される。
- この手法ならば、各入力欄の制限長を超えるコードも“複数回に分けて”注入できる。
- 以上より「HTMLがコメントアウトされ一つのスクリプトになるような投稿を複数回に分けて行った。」が適切な解答となる。
誤りやすいポイント
- 1件のレビューだけでスクリプト全体を埋め込んだと考えてしまい、コメントアウトの役割を見落とす。
- コード長制限の回避方法を「改行を入れた」と誤記し、分割投稿という本質を外す。
- XSS対策不足(エスケープ不足)とCookie盗難(HttpOnly未設定)を混同し、本問の「文字数制限突破」の着眼点から逸れる。
FAQ
Q: コメントアウトを利用するとブラウザはどのように動作しますか?
A: /* から */ まではコメントとみなしスクリプトを実行しません。そのため複数の入力欄に交互に配置すると、実行対象コードとコメントが意図どおりに結合されます。
A: /* から */ まではコメントとみなしスクリプトを実行しません。そのため複数の入力欄に交互に配置すると、実行対象コードとコメントが意図どおりに結合されます。
Q: レビュー詳細欄ではなくタイトル欄が狙われたのはなぜですか?
A: タイトルは一覧表示で連続して並ぶため、分割したコードを確実に隣接させられ、ブラウザが1本の <script> として結合しやすいからです。
A: タイトルは一覧表示で連続して並ぶため、分割したコードを確実に隣接させられ、ブラウザが1本の <script> として結合しやすいからです。
Q: コード長制限への対策は何をすべきですか?
A: サーバ側で入力内容をHTMLエスケープするほか、スクリプトタグやイベントハンドラ文字列を検知・除去するフィルタリングを併用し、単純な文字数制限だけに頼らないことが重要です。
A: サーバ側で入力内容をHTMLエスケープするほか、スクリプトタグやイベントハンドラ文字列を検知・除去するフィルタリングを併用し、単純な文字数制限だけに頼らないことが重要です。
関連キーワード: XSS, コメントアウト、Scriptインジェクション、Cookie盗難、XMLHttpRequest
(1)図4の6〜20行目の処理の内容を、60字以内で答えよ。
模範解答
XHRのレスポンスから取得したトークンとともに、アイコン画像としてセッションIDをアップロードする。
解説
解答の論理構成
- 図4の6:行目でxhr.onload = function() が定義され、1回目のリクエスト完了後に以降の処理が実行されます。
- 7:行目でpage = xhr.response; とし、4:行目のxhr.responseType = "document"; によって取得したDOMを格納します。
- 8:行目のtoken = page.getElementById("token").value; で、会員プロフィール画面に埋め込まれているCSRF対策用トークンを抽出します。
- 9:〜11:行目でxhr2を生成し、url2 = "https://[□□□].co.jp/user/upload"; へPOST送信する準備をします。
- 12:〜18:行目ではFormDataを組み立てます。特に
・13:行目でcookie = document.cookie; として被害者ブラウザ内のcookie(セッションIDを含む)を取得
・16:行目でfile = new File([cookie]、fname, {type: ftype}); とし、cookie文字列をファイル内容とする擬似画像を生成
・17:行目でform.append("uploadfile"、file); としてファイルを、18:行目でform.append("token"、token); としてトークンを追加 - 19:行目のxhr2.send(form); でアップロードを実行し、被害者のセッションIDを画像ファイルとしてサーバへ送信します。
- 以上より「1回目のXHRでトークンを取得 → 自身のcookieをファイルに偽装 → 正規トークン付きでアップロード」という攻撃フローになるため、模範解答の内容となります。
誤りやすいポイント
- document.cookieの送信を「直接POSTパラメータで送る」と誤解し、ファイルオブジェクト化している点を見落とす。
- tokenをCSRFトークンではなく「ファイル名」や「パスワード」と読み違える。
- xhr.responseType = "document" の意味を把握できず、HTML解析を伴うことに気付かない。
- 1回目と2回目のXMLHttpRequestを区別できず、両者の役割を混同する。
FAQ
Q: なぜセッションIDを画像ファイルに偽装して送るのですか?
A: アップロードAPIは画像ファイルしか受け付けないため、Fileオブジェクトを作成して中身にcookieを詰め、形式だけimage/pngにすることでバイパスしています。
A: アップロードAPIは画像ファイルしか受け付けないため、Fileオブジェクトを作成して中身にcookieを詰め、形式だけimage/pngにすることでバイパスしています。
Q: tokenを取得する目的は何ですか?
A: "https://□□□.co.jp/user/upload" はCSRF対策として "token" パラメータを要求します。攻撃者は1回目のリクエストで正規トークンを盗み、2回目のアップロードを正当なリクエストに見せかけています。
A: "https://□□□.co.jp/user/upload" はCSRF対策として "token" パラメータを要求します。攻撃者は1回目のリクエストで正規トークンを盗み、2回目のアップロードを正当なリクエストに見せかけています。
Q: この攻撃で最終的に何が危険になるのですか?
A: 攻撃者は被害者のセッションIDを自分が閲覧できる場所(たとえば自分のアカウントのアイコン画像)に保存させ、後で取得して乗っ取ることが可能になります。
A: 攻撃者は被害者のセッションIDを自分が閲覧できる場所(たとえば自分のアカウントのアイコン画像)に保存させ、後で取得して乗っ取ることが可能になります。
関連キーワード: XSS, XMLHttpRequest, cookie, CSRFトークン、セッションID
(2)攻撃者は、図4のスクリプトによってアップロードされた情報をどのようにして取得できるか。取得する方法を、50字以内で答えよ。
模範解答
会員のアイコン画像をダウンロードして、そこからセッションIDの文字列を取り出す。
解説
解答の論理構成
- 図4のスクリプトではdocument.cookieを変数cookieに格納し(行13)、被害者ブラウザ内のセッションIDなどを取得します。
- 行16でnew File([cookie]、fname, {type: ftype}); を実行し、cookie文字列を内容とするファイルa.png(MIMEタイプは "image/png")を生成します。
- 行17でform.append("uploadfile"、file); として、レビュー機能と同一サイト内のアイコン画像アップロードAPIである "https://□□□.co.jp/user/upload"(行10)へ送信します。
- 図1の説明より、アップロードされたアイコン画像は「会員プロフィール設定ページやレビュー専用ページに表示される」とあります。つまりファイルは公開URL /users/●●●/icon.pngで誰でも参照可能になります。
- 攻撃者は後から当該URLをダウンロードするだけで、画像の中身として保存されたcookie(=被害者のセッションID)を取得できます。
- したがって問われている「アップロードされた情報の取得方法」は「公開されたアイコン画像を取得して中身を読む」ことになります。
誤りやすいポイント
- XHR2のレスポンスを利用して情報を直接窃取すると誤解しやすいが、実際にはアイコン画像として保存されたファイルを後から盗み見る手口です。
- 「HttpOnlyが付いていないからcookieを読める」点は条件であって、取得方法そのものではありません。
- ファイル名やMIMEタイプを画像に偽装しているため、画像ビューアで開くと空白に見えて気付きにくいことがあります。
FAQ
Q: なぜ被害者ユーザのパスで保存された画像URLを攻撃者が知り得るのですか?
A: 多くのサイトではプロフィールページのHTMLにアイコン画像の絶対パスが埋め込まれるため、攻撃者が同ページを閲覧すればURLを得られます。
A: 多くのサイトではプロフィールページのHTMLにアイコン画像の絶対パスが埋め込まれるため、攻撃者が同ページを閲覧すればURLを得られます。
Q: もしHttpOnly属性が付与されていたら、この攻撃は成立しますか?
A: document.cookieが取得できなくなるため、少なくともセッションIDを画像に書き込む部分は失敗します。
A: document.cookieが取得できなくなるため、少なくともセッションIDを画像に書き込む部分は失敗します。
Q: 画像形式チェックが有効なら防げますか?
A: チェックが拡張子やMIMEタイプだけなら回避可能です。バイナリ検査でPNGシグネチャを検証すれば無効化できます。
A: チェックが拡張子やMIMEタイプだけなら回避可能です。バイナリ検査でPNGシグネチャを検証すれば無効化できます。
関連キーワード: XSS, CSRF, セッションID, MIMEタイプ偽装、cookie盗聴
(3)攻撃者が(2)で取得した情報を使うことによってできることを、40字以内で答えよ。
模範解答
ページVにアクセスした会員になりすまして、WebアプリQの機能を使う。
解説
解答の論理構成
- スクリプトが取得する情報
- 図4行 13: cookie = document.cookie; でブラウザに保存されたcookieを取得しています。
- そのcookieが意味するもの
- 【問題文】図1「ログイン機能」には
“ログインした会員には、セッションIDをcookieとして払い出す。”
とあり、cookie内には会員の セッションID が格納されています。
- 【問題文】図1「ログイン機能」には
- 攻撃者がcookieを入手できる理由
- 図4行 17: form.append("uploadfile"、file); でcookie文字列をファイル内容にしてアップロードし、行 19: xhr2.send(form); で攻撃者が用意した https://[□□□].co.jp/user/upload に送信します。
- WebアプリQは「cookieにHttpOnly属性を付与していない」ため、JavaScriptから自由に読み取れます。
- セッションIDを得た攻撃者が可能になる行為
- セッションIDは本人確認に利用される唯一の情報であり、これを保持すればサーバはアクセス元を会員本人だと誤認します。
- その結果、攻撃者は 「ページVにアクセスした会員になりすまして、WebアプリQの機能を使う。」 ことができます。
誤りやすいポイント
- 「tokenだけで攻撃できる」と誤解し、cookieの重要性を見落とす。
- 「画像アップロードだから無害」と考え、ファイルにセッションIDが埋め込まれる点に気付かない。
- HttpOnly属性が付いていない設定を読み飛ばし、「JavaScriptからcookieは読めない」と判断してしまう。
- CSRFと混同し、「被害は勝手な投稿が行われる程度」と限定的に捉える。
FAQ
Q: なぜ攻撃者サイトではなく https://□□□.co.jp 宛てにアップロードしているのですか?
A: 同一生成元ポリシーを回避するためです。正規ドメインへの送信であればブラウザは警告を出さず、攻撃者は後でサーバからファイルを取得して内容(cookie)を読めます。
A: 同一生成元ポリシーを回避するためです。正規ドメインへの送信であればブラウザは警告を出さず、攻撃者は後でサーバからファイルを取得して内容(cookie)を読めます。
Q: HttpOnly属性を付ければ今回の攻撃は防げますか?
A: JavaScriptからcookieを読めなくなるので、少なくともセッションIDの窃取は防止できます。ただし他にもXSSやアップロード処理の検証不足など複数の問題があるため、包括的な対策が必要です。
A: JavaScriptからcookieを読めなくなるので、少なくともセッションIDの窃取は防止できます。ただし他にもXSSやアップロード処理の検証不足など複数の問題があるため、包括的な対策が必要です。
Q: 画像形式チェックが甘い点は何と関係していますか?
A: 攻撃者が実際には テキストファイル(セッションID入り)を image/png と偽ってアップロードできるため、サーバに敏感情報を保存させるのに利用されています。
A: 攻撃者が実際には テキストファイル(セッションID入り)を image/png と偽ってアップロードできるため、サーバに敏感情報を保存させるのに利用されています。
関連キーワード: XSS, セッションハイジャック、HttpOnly, Same-Origin Policy, FormData
設問4:
問題文を見る仮に、攻撃者が用意したドメインのサイトに図4と同じスクリプトを含むHTMLを準備し、そのサイトにWebアプリQのログイン済み会員がアクセスしたとしても、Webブラウザの仕組みによって攻撃は成功しない。この仕組みを、40字以内で答えよ。
模範解答
スクリプトから別ドメインのURLに対してcookieが送られない仕組み
解説
解答の論理構成
- 図4のスクリプトは
2: url1 = "https://[□□□].co.jp/user/profile";
に対してXMLHttpRequestを発行し、レスポンスから8: token = page.getElementById("token").value; を取得しようとしています。 - ところが、想定シナリオではこのJavaScriptが「攻撃者が用意したドメイン」で実行され、https://[□□□].co.jp とは別ドメインになります。
- ブラウザは別ドメインに対して送信するXMLHttpRequestでは、明示的に
xhr.withCredentials = true;
を指定しない限り、当該ドメインのcookie(セッションIDなど)を自動送信しません。図4にはこの設定が存在しません。 - その結果、https://[□□□].co.jp/user/profile へのリクエストにはログイン状態を示すcookieが付かず、サーバは会員ページを表示せずにログインページ等を返します。よってpage.getElementById("token") は取得できず、続く
18: form.append("token"、token);
も失敗し、攻撃は成立しません。 - 以上より、設問が求める “Webブラウザの仕組み” は
スクリプトから別ドメインのURLに対してcookieが送られない仕組み
であると論理的に導けます。
誤りやすいポイント
- 「同一生成元ポリシーでレスポンスが読めない」と思い込み、cookie送信の可否を見落とす。
- HttpOnly属性の有無が原因と誤解する(ここではcookieがそもそも送られないことがポイント)。
- withCredentialsの既定値がfalseであることを忘れ、クロスサイトでもcookieが付くと考えてしまう。
FAQ
Q: xhr.withCredentials = true; を攻撃者が追加すれば成立しますか?
A: 送信自体は可能になりますが、サーバ側でCORS設定が無い場合、レスポンスをJavaScriptで読むことはできません。さらなる条件が必要です。
A: 送信自体は可能になりますが、サーバ側でCORS設定が無い場合、レスポンスをJavaScriptで読むことはできません。さらなる条件が必要です。
Q: 同一生成元ポリシーと今回の仕組みは何が違いますか?
A: 同一生成元ポリシーは「別ドメインのレスポンスをJSが参照できない」仕組み、今回のポイントは「別ドメインへリクエストする際にcookieが自動送信されない」仕組みです。
A: 同一生成元ポリシーは「別ドメインのレスポンスをJSが参照できない」仕組み、今回のポイントは「別ドメインへリクエストする際にcookieが自動送信されない」仕組みです。
Q: ブラウザをまたがずにサーバ側だけで防ぐ方法はありますか?
A: SameSite=LaxやSameSite=Strictをcookieに付与すれば、クロスサイトリクエスト時の送信をブラウザ任せで一段と制限できます。
A: SameSite=LaxやSameSite=Strictをcookieに付与すれば、クロスサイトリクエスト時の送信をブラウザ任せで一段と制限できます。
関連キーワード: Same-Origin Policy, CORS, XMLHttpRequest, withCredentials, セッションID




