情報処理安全確保支援士過去問題 令和6年春期 午後 問1

⇄問題PDFと解説を画面2分割で開く⇱問題PDF

設問1

解答入力欄

  • a:

解答例・解答の要点

  • a:ステートレス

解説

RESTful APIは、WebサービスやAPIを設計するためのアーキテクチャであるREST(Representational State Transfer)の原則に基づいて設計されたAPIです。RESTful APIの設計原則は一般的とは次の4つをいいます。クライアントサーバ方式とオンデマンドコードの2つを追加して6原則とすることもあります。
統一インターフェイス
GET(取得)、POST(入力)、PUT(更新)、DELETE(削除)の4つのHTTPメソッドを使用して情報を操作する
アドレス可能性
サーバ上のデータやサービスは一意なURIによって識別する
ステートレス
サーバはクライアントの状態を保持せず、リクエストは独立して完結する
接続性
レスポンスとしてリソースの状態と操作可能なリンクを含む
「セッション管理を行わないという性質」ですから、空欄aには「ステートレス」が当てはまります。

ステートレスは、サーバはクライアントのセッション情報や過去のリクエストの状態を保存しないという性質です。クライアントから送信されるリクエストはそれ自体が完全な情報を持っていて、サーバはリクエストを受け取るたびにそのリクエストの内容だけをもとに処理を行います。これにより容易な負荷分散やシンプルなサーバ実装が可能となります。ステートレスとは逆に、サーバがクライアントの情報を保持し続け、その内容が出力にも反映される性質を「ステートフル」と呼びます。

a=ステートレス

設問2

解答入力欄

    • b:
    • データ:
    • 内容:
    • c:
    • d:

解答例・解答の要点

    • b:500
    • データ:
      JWTヘッダ内のalgに指定された値
    • 内容:
      NONEでないことを検証する。
    • JWTに含まれる利用者IDがmidの値と一致するかどうかを検証する処理
    • c:共通モジュールP
    • d:連続失敗回数がしきい値を超えたらアカウントをロックする処理
  • 解説

    • 表2によると、文字列Xは数字4桁の文字列であるため、0000~9999の10,000通りとなります。0000から9999まで1ずつ増やしながら試行していく場合、文字列Xが0000だった場合は1回、文字列Xが9999だった場合は10,000回の試行が必要となります。文字列Xはランダムに生成される一様分布なので、突破までの平均試行回数は「(1+10,000)÷2=5,000.5回です。1秒間に10回試行されるので0.1秒/回、5,000.5回の試行に要する時間は「5,000.5回×0.1秒=500.05秒」と計算でき、小数点以下を四捨五入すると500秒です。したがって、空欄bには「500」が入ります。表2によると文字列Xの有効期限は10分(600秒)なので、平均500秒であれば突破されてしまう可能性が十分に高いと言えます。

      ∴500

    • REST APIはステートレスなのでサーバ側でセッション情報を保持しません。ユーザー認証が必要なAPIを実装するために使用される技術がJWT(JSON Web token)です。HTTPリクエストにJWTを乗せることで、サーバ側では利用者の認証と識別ができるようになります。

      問題文では「JWTのヘッダ内のalgの値を"NONE"にしたところ,ペイロードの"user01"を他の利用者IDに改ざんしてもJWTの検証が成功した」とあります。これは「alg=none攻撃」と呼ばれ、署名の検証に用いるアルゴリズムの値に検証を行わないことを意味する'NONE'を指定することで、サーバ側のJWT検証を回避するものです。JWTの標準化規格であるRFC7519によれば、JWTは署名や暗号化なしで作成することもでき、この場合、algヘッダーの値として「none」を指定することになっています。

      この脆弱性に対しては、JWTの仕様上の特別な値である"alg=NONE"を拒否することが必要ですから、修正後のライブラリQで行うべき検証は、JWTヘッダ内のalgの値がNONEでないことの確認となります。

      ∴データ=JWTヘッダ内のalgに指定された値
       内容=NONEでないことを検証する。

    • 下線③の対策は、表3項番2の「パラメータmidに他の利用者IDを指定すると,他の利用者IDにひも付く利用者情報を取得,改変できてしまう」という脆弱性に関するものです。P呼出し処理は、サービスL内の利用者管理共通ライブラリ(共通モジュールP)を呼び出す処理であり、GETメソッドを使って利用者情報の取得、PUTメソッドを使って利用者情報の更新を行うAPIであると表2に記述されています。

      表3項番2の脆弱性は、JWTの発行後に、GETメソッドで利用者情報を取得しようとするとき、mid(利用者ID)に他人のものを指定すると、そのまま他人の利用者情報が取得できてしまうというものです。つまり、JWTの検証だけが行われ、midの検証が行われていません。リクエストとともに送信されるJWTにはペイロード部の"user"パラメータの値として利用者IDが含まれるため、この情報と送られてきたmidの値と照合する処理を加えることにより対策をすることが可能です。

      ∴JWTに含まれる利用者IDがmidの値と一致するかどうかを検証する処理

    • 表5項番3の対策は、表3項番3の「利用者APIで利用者情報を更新する場合、"paid"という値を設定したパラメータ"status"を追加して送信すると,利用者ステータスを無償利用者から有償利用者に改変できてしまう」という脆弱性に関するものです。利用者情報の更新ということなので、利用者APIのPUTメソッドの項を見てみると、更新対象として"name(名前)"と"age(年齢)"だけが対象となっていますが、値のチェックをしていないのでしょう。データベース(サービスM)上のステータスの値も変更可能になってしまっています。

      表2の利用者APIの仕様より、S-APIへのリクエストは次の流れで行われます。
      1. サービスK(ゲートウェイ)が一元的に受け付ける
      2. サービスKはリクエスト内容に基づきサービスLを呼び出す
      3. サービスLは内部に定義された共通モジュールPを呼び出す
      4. 共通モジュールPはサービスM(データベースサーバ)を呼び出す
      したがって、APIのパラメータを受取り、利用者ステータスを変更できる構成要素は「共通モジュールP」となります。共通モジュールへの変更は難しいので、サービスLのプログラムに更新可能なパラメータであるかを検証する処理を追加する必要があります。

      c=共通モジュールP

    • 表5項番4は、表3項番4の総当たり攻撃による2要素認証の突破という脆弱性に関するものです。「dを実装する。しきい値は10回とする」という文言および総当たり攻撃への一般的な対策を踏まえると、アカウントのロックアウトが当てはまると判断できます。ロックアウトとは、一定回数以上連続してログイン試行に失敗した場合に、一時的にログインを不能とする仕組みです。攻撃者が試行できる回数が制限されるため、総当たり攻撃の成功確率を大幅に低下させることができます。

      解答文字数が少なければロックアウトだけでもよさそうですが、「適切な処理内容を30字以内で」という条件があるので、文脈を考えると「認証にしきい値以上の回数連続で失敗した場合、アカウントをロックする処理」などロックアウトの具体的な処理内容を含めた説明が求められます。

      d=連続失敗回数がしきい値を超えたらアカウントをロックする処理

    設問3

    解答入力欄

      • e:
      • f:
      • 利点:
      • 内容:

    解答例・解答の要点

    • テストサーバのindex.htmlへのアクセスを記録し,確認する仕組み
    • e:Header
    • f:Header
    • ・¥W[jJ] [nN] [dD] [iI]¥W
      ・¥W(j|J)(n|N)(d|D)(i|I)¥W
    • 利点:誤検知による遮断を防ぐことができる。
    • 内容:アラートを受信したら攻撃かどうかを精査する。
  • 解説

    本問で題材となっている脆弱性Vは、Log4Shell(CVE-2021-44228)として知られるものです。Log4Shellは、Javaで書かれたオープンソースのロギングフレームワークであるLog4jに存在する脆弱性です。この脆弱性は、Javaアプリケーションが外部サーバにアクセスしてデータやオブジェクトをダウンロード&実行する仕組みであるJNDIルックアップと、ログメッセージ中の変数をルックアップ置換するLog4jの機能を組み合わせて、外部から任意のコードを実行するものです。大まかな攻撃のシナリオとしては次のようになります。
    1. リモートからLDAP経由で参照先を取得するJNDIコマンドを用意する。これは、$(jndi:ldap://・・・)という形式になる
    2. 1.で用意したコマンドを、HTTPヘッダーのX-Api-Versionなどに含めて攻撃対象サーバに送信する
    3. 攻撃対象サーバがHTTPヘッダーをログに記録する際、Log4jの機能により変数が置換えされる。この時にJNDIルックアップが実行される
    4. LDAPサーバは、攻撃コードを含むファイルを参照先として返す
    5. 攻撃対象サーバは、攻撃コードを含むファイルをダウンロードし、実行する
    • 図8の文字列をパラメータに含むHTTPリクエストを攻撃対象サーバが受信すると、そのログが記録される際に「ldap://」で始まるURLで外部の攻撃用LDAPサーバにアクセスが行われます。図6の手順(4)~(6)にはその後、攻撃対象サーバでコマンドが実行されるまでの流れが説明されています。
      1. LDAPリクエストWから、デコードした状態のコマンドCを取り出す
      2. 攻撃用HTTPサーバに、コマンドCを実行するJavaクラスファイル(Jファイル)を配置する
      3. 攻撃対象サーバに、JファイルのURL(URL-J)を返す
      4. 攻撃対象サーバは、URL-Jにアクセスして、Jファイルをダウンロードし、記述されたコマンドを実行する
      図8で指定したコマンドCは「wget http://a2.b2.c2.d2/index.html」となっています(wgetは指定されたURLからファイルをダウンロードするLinuxのコマンドです)。テストサーバが図8のコマンドを受け取った場合、テストサーバ上に「wget http://a2.b2.c2.d2/index.html」を実行するJavaクラスファイルが作成され、それが攻撃対象サーバ上にダウンロードされて実行されることになります。

      一連の流れが成功すると、テストサーバ(a2.b2.c2.d2)の「index.html」にアクセスが発生します。このアクセスを記録・確認できる仕組みを実装すれば、指定したコマンドが攻撃対象サーバで実行されたことを確認できます。

      ∴テストサーバのindex.htmlへのアクセスを記録し,確認する仕組み

    • 図5のWAFルールの記述形式を見ると、検査対象に指定できるのはGET等の7種類です。図6の手順(3)に「準備した攻撃コードをHTTPリクエストのx-api-versionヘッダの値として指定したHTTPリクエストを攻撃対象サーバに送信する」とあるように、この攻撃ではHTTPヘッダーに$(jndi:ldap://・・・)という形式の不正な値を指定することで、ログに書き込ませようとします。したがって、jndi、ldapのいずれもWAFの検査対象はヘッダー部であり、これを可能とするWAFルールの指定は「Header」となります。

      なお、x-api-versionは一例で、Referer、Accept-Language、Cookie、User-Agentなどのヘッダーフィールドも攻撃に使用されます。

      e=Header
       f=Header

    • 現在のパターンである¥Wjndi¥Wは、"jndi"という小文字にのみマッチするため、1文字でも大文字が含まれるとマッチしません。大文字・小文字を問わずにマッチさせるには、jとnとdとiの4文字に分け、それぞれを大文字・小文字両方にマッチするように記述する必要があります。図5の正規表現のパターンを参考にすると、これを実現するには次の2つのいずれかを使うことになります。
      • x|y x又はyとマッチする
      • [xyz] x、y又はzのいずれかにマッチする
      大文字Jと小文字jのいずれかにマッチする正規表現は[jJ]または(j|J)と記述できるので、同様にnとdとiの文字を順に並べて[jJ][nN][dD][iI]または(j|J)(n|N)(d|D)(i|I)とすれば、それぞれの小文字または大文字とマッチするようになります。[Jj][Jj]のように大文字と小文字の前後は逆でも構いません。一応、¥W(jndi|Jndi|JNdi|JnDi|…|JNDI)¥Wというように全16パターンを全部記述しても正しく動作はします。

      補足として、前後に¥Wを付けているのは、英単語の一部に含まれているのではなく、"jndi"と単独で存在している場合にマッチさせる必要があるからです。また、実際の攻撃では変数を入れ子にして難読化するなどしてWAF回避策がとられますので、R氏が行った正規表現の変更は一時的な回避策という位置付けで、E社から網羅的な正規表現パターンが提供されたら、そちらを適用することになります。

      ∴¥W[jJ][nN][dD][iI]¥W 又は ¥W(j|J)(n|N)(d|D)(i|I)¥W

    • 図5によると、WAFルールに指定できる動作には『許可』『検知』『遮断』があり、『検知』は「通信を通過させ,ログに記録し,管理者にアラートを送信する」、『遮断』は「通信を遮断し,ログに記録し,管理者にアラートを送信する」とあります。すなわち、『遮断』と『検知』の違いは、通信を通過させるか遮断させるかの違いとなります。

      セキュリティの観点からは、通信を遮断する方がより安全です。しかし、WAFルールに指定した「Header」では全てのヘッダーの値を検証対象とするため、誤検知が発生する可能性があると考えられます。必要な通信まで遮断されてしまった場合、サービスYの提供に支障を来たすおそれがあります。本来であれば、事前に十分なテストを行うことが望ましいですが、図6によると、すでに脆弱性Vが悪用された事例が報告されており、時間的な余裕がありません。このような背景より、WAFの動作を『検知』として通信は通過させつつも、ログへの記録と管理者へのアラート送信で攻撃を監視する折衷案を採用したものと考えられます。この設定により、サービスへの影響を抑えつつ、脆弱性を突いた攻撃への対策をとることができます。

      ∴利点:誤検知による遮断を防ぐことができる。

      次に、被害を最小化するために実施すべき内容ですが、『検知』は通信を通過させているので、もしその通信が攻撃だった場合、何も対策を講じなければ攻撃者に後続の攻撃を許してしまう可能性があります。このリスクを防ぐためには、検知された通信が攻撃であるかどうかを確認し、攻撃と判断された場合には適切な対処を実施する必要があります。検知した場合は管理者にアラートが送信されるので、アラートを受信したタイミングでその通信内容をチェックして攻撃であるかどうかを調べ、攻撃と判断した場合はしかるべき対応をとることが求められます。

      ∴内容:アラートを受信したら攻撃かどうかを精査する。
    © 2014-2024 情報処理安全確保支援士ドットコム All Rights Reserved.

    Pagetop