更新履歴(1件・最終更新 2026年08月07日)
この記事に加えた変更の記録です。アーカイブした更新前のバージョンは、DOI付きの固定URLから読めます。
- 記事の冒頭に「この記事の知識マップ」節を追加しました。本文で扱う概念とその関係を、要約・図・詳細ページへのリンクにまとめました。本文の主張は変えていません。
- 初版公開
「JWTの署名を検証しているから、利用者IDは信用できる」
この言い方は、半分だけ正しいものです。
情報処理安全確保支援士試験 令和6年度 春期 午後 問1は、スマートフォンから呼び出すAPIを題材にしています1。認証に成功するとJWTが発行され、そのJWTを付けて利用者情報の取得・更新APIを呼び出します。一見すると、よくある構成です。
ところが、診断では次の四つが見つかります。
- JWTヘッダの
algをnoneへ変更すると、署名なしのJWTが通る - 正しいJWTを使ったまま
midを別の利用者IDへ変えると、他人の情報を取得・更新できる - 仕様にない
status=paidを追加すると、無償利用者が有償利用者へ変わる - メールで届く4桁の認証コードを、制限なく総当たりできる
四つとも「認証まわりの脆弱性」に見えますが、原因は同じではありません。トークンの完全性、オブジェクト単位の認可、プロパティ単位の認可、試行回数制限という別々の境界が破られています。
後半では、さらに別の論点が加わります。広く利用されているオープンソースライブラリに、JNDI Lookupを悪用して外部からコードを実行できる重大な脆弱性が公表されます。修正版も完成したWAFルールもまだない。その間に、どう影響を確かめ、どこをWAFで見て、なぜ最初は「遮断」ではなく「検知」にするのかを問われます。
この記事では、公式の解答例2と採点講評3を土台に、各設問の答えだけでなく、なぜその答えになるのか、実務ではどこまで強く設計するべきかまで整理します。
flowchart TB
accTitle: 問題全体像
accDescr: 認証コード、JWT、API認可、ライブラリ脆弱性の各段階で破られる信頼境界を示す
user[利用者アプリ]
auth[4桁認証コード]
jwt[JWT発行]
api[利用者API]
log[ログ出力]
vuln[脆弱なライブラリ]
ext[外部コード実行]
user --> auth
auth -->|試行回数制限なし| jwt
jwt -->|alg=noneを許可| api
api -->|midを信用| db1[他人のデータ取得/更新]
api -->|status=paid| db2[課金状態の変更]
api --> log
log --> vuln
vuln -->|JNDI/LDAP/HTTP| ext
図1: 問題全体像。各段階で別の信頼境界が破られている。
1.まず結論
- RESTful APIがセッションを持たない性質はステートレス。ただし、サーバがデータベースや利用者状態を一切持たないという意味ではない
- 4桁の認証コードは1万通り。1秒10回なら平均5,000回、500秒で成功する。有効期間10分より短いので、失効時間だけでは防げない
alg=noneへの最低限の対策は、JWTヘッダのalgがNONEでないことを確認すること。ただし実務では、許可するアルゴリズムをサーバ側で固定する- JWTが正しくても、リクエストの
midを信用してはいけない。JWT内の利用者IDとmidを照合するか、より安全にはmidを受け取らずJWTから対象を決める status=paidの追加は、仕様外のプロパティまで内部オブジェクトに結び付けるMass Assignmentの問題。更新用DTOを許可リストとして使い、課金状態は利用者に変更させない- 総当たり対策の解答は、連続失敗回数がしきい値を超えたらアカウントをロックする処理。実務では段階的遅延や送信元単位の制御も重ねる
- 新しい重大脆弱性の影響確認では、破壊的な命令ではなく、テストサーバの
index.htmlへのアクセスを記録して外部コード実行の到達を確認する - 攻撃文字列はHTTPヘッダに入るので、WAFの検査対象は
Header。大文字・小文字の入替えに対応する正規表現として、例えば\W[jJ][nN][dD][iI]\Wを使う - WAFを最初に「検知」にする利点は、誤検知による業務通信の遮断を防げること。アラートを受けたら攻撃かどうかを精査し、調整後に遮断へ移す
- WAFは暫定対策であり、根本対策は影響を受けるライブラリを修正版へ更新すること
この記事の知識マップ
令和6年春の情報処理安全確保支援士午後問1は、RESTful APIのステートレスな要求に対して認証と認可を別々に設計する重要性を問う問題です。JWTの署名検証はalg=noneを許すとアカウント乗っ取りに通じ、認証が済んでもオブジェクト単位(BOLA)やプロパティ単位(Mass Assignment)の認可を欠くと他人のデータや有償状態が書き換えられます。4桁の短期認証コードは総当たりに弱く、試行回数制限で軽減します。Log4Shell型の脆弱性ではJNDI Lookupが外部コード実行を招き、WAFは修正版ライブラリへの更新が出るまでの暫定緩和に位置づけられます。
flowchart LR
accTitle: 情報処理安全確保支援士 令和6年春午後問1(APIセキュリティ)の知識マップ
accDescr: RESTful APIのステートレスな信頼境界、JWT署名検証とalg=none、認証と認可の分離、オブジェクト・プロパティ単位の認可不備、4桁認証コードの総当たり、Log4ShellのJNDI LookupとWAFの暫定対策の関係を示す図
rest_api["REST API"]
jwt["JWT(JSON Web Token)"]
authorization["認可"]
waf["WAF(Web Application Firewall)"]
stateless["ステートレス"]
authentication["認証"]
jwt_signature_verification["JWT署名検証"]
jwt_allowed_algorithms["JWT許可アルゴリズムリスト"]
account_takeover["アカウント乗っ取り"]
jwt_alg_none["JWTのalg=none攻撃"]
bola["BOLA(オブジェクト単位の認可不備)"]
unauthorized_data_access["未許可データアクセス"]
update_dto_allowlist["更新用DTOの許可リスト"]
mass_assignment["Mass Assignment(プロパティ単位の認可不備)"]
privilege_escalation["権限昇格"]
four_digit_auth_code["4桁認証コード"]
brute_force["総当たり攻撃(ブルートフォース)"]
account_lockout["アカウントロック"]
log4shell["Log4Shell(CVE-2021-44228)"]
jndi_lookup["JNDI Lookup"]
arbitrary_code_execution["任意コード実行"]
library_update["ライブラリの修正版への更新"]
waf_detection_mode["WAF検知モード"]
waf_blocking_mode["WAF遮断モード"]
rest_api -->|"前提とする"| stateless
authentication -->|"より先に行うべき"| authorization
jwt -.->|"利用する"| jwt_signature_verification
jwt_signature_verification -->|"で構成できる"| jwt_allowed_algorithms
jwt_allowed_algorithms -.->|"防止する"| account_takeover
jwt_alg_none -.->|"原因になり得る"| account_takeover
authorization -.->|"防止する"| bola
bola -.->|"原因になり得る"| unauthorized_data_access
update_dto_allowlist -.->|"防止する"| mass_assignment
mass_assignment -.->|"原因になり得る"| privilege_escalation
four_digit_auth_code -.->|"原因になり得る"| brute_force
brute_force -.->|"原因になり得る"| account_takeover
account_lockout -.->|"軽減する"| brute_force
log4shell -->|"利用する"| jndi_lookup
jndi_lookup -.->|"原因になり得る"| arbitrary_code_execution
waf -.->|"軽減する"| log4shell
library_update -.->|"防止する"| log4shell
waf_detection_mode -.->|"より先に行うべき"| waf_blocking_mode
図の実線は常に成り立つ関係、破線は条件付きの関係です(成立条件は詳細ページの各関係の説明に記載)。関係すべての一覧(全18件、根拠・確度つき)と主要概念の定義は知識マップ詳細ページにまとめています。データ: JSON-LD / Turtle
2.題材と設問の対応
問題の舞台は、ヘルスケアサービスを新規に提供しようとしているG社です。利用者はスマートフォンアプリから食事や体重などを入力し、健康リスクの判定や食事メニューの助言を受けます。システムはクラウド上に構築され、APIゲートウェイ、イベント駆動の処理、マネージドデータベースを組み合わせています。
問題文の製品名やサービス名は抽象化されています。本記事も、IPAの図表や文章を転載せず、設問を理解するために必要な構造だけを言い換えます。
| 設問 | 主題 | 本記事の章 |
|---|---|---|
| 設問1 | RESTful APIの性質 | 4章 |
| 設問2(1) | 4桁コードの総当たり時間 | 5章 |
| 設問2(2) | JWTのalg=none |
6章 |
| 設問2(3) | midを使った他人へのアクセス |
7章 |
| 設問2(4) | 仕様外のstatusを受け入れる不備 |
8章 |
| 設問2(5) | 総当たり対策 | 9章 |
| 設問3(1) | 安全な方法で脆弱性の存在を確かめる | 11章 |
| 設問3(2)(3) | WAFで見る場所と正規表現 | 12章 |
| 設問3(4) | 検知モードの利点と運用 | 13章 |
採点講評では、全体の正答率は平均的だったとされています。一方、設問2(2)のJWT改ざん対策と、設問3(1)の検証用サーバに必要な仕組みは、正答率がやや低かったと指摘されています。どちらも、単語だけを知っていても解けません。攻撃者がどの値を変え、それがどの処理へ流れ、どこで信頼されてしまったかを追う必要があります。
3.この問題は「認証の問題」一つではない
問題全体を、信頼境界ごとに並べると次のようになります。
[利用者ID・パスワード]
|
v
[4桁コードの確認] ---- 試行回数制限なし ----> 総当たり
|
v
[JWTを発行]
|
v
[JWTライブラリ] ------- alg=noneを許可 ------> 利用者IDの改ざん
|
v
[利用者API]
| |
| +-- statusを丸ごと渡す ----> プロパティ単位の認可不備
|
+-- midを信用する -----------------------> オブジェクト単位の認可不備
[外部入力をログへ記録]
|
v
[脆弱なライブラリ] ---- JNDI/LDAP/HTTP ------> 外部コード実行
ここで最も大切なのは、次の区別です。
| 確認 | 問うこと | この問題で破られた例 |
|---|---|---|
| 認証 | あなたは誰か | 4桁コードの総当たり |
| トークン検証 | その身元情報は改ざんされていないか | alg=none |
| オブジェクト単位の認可 | その利用者のデータへアクセスしてよいか | midの差替え |
| プロパティ単位の認可 | その項目を変更してよいか | status=paid |
| 入力から実行への境界 | 外部入力が命令として解釈されないか | JNDI Lookup |
一つ前の確認に成功したことは、次の確認を省略してよい理由になりません。 正しいJWTを持つ利用者でも、他人のデータを読んでよいとは限りません。自分のデータを更新できる利用者でも、課金状態まで変更してよいとは限りません。
この段階分けができると、設問ごとの答えが暗記ではなくなります。
flowchart LR
accTitle: 認証と認可の違い
accDescr: 認証が主体を確認し、認可がその主体に許可された操作を確認する
auth[認証<br/>誰であるか]
authz[認可<br/>何をしてよいか]
auth --> authz
図2: 認証と認可の違い。認証が先で、認可は別の確認である。
4.設問1 ── ステートレスとは何か
設問1は、RESTful APIの設計原則の一つで、セッション管理を行わない性質を問います。
解答は ステートレス です。
ステートレスとは、サーバが一つ前のリクエストの会話状態を覚えておかなくても、各リクエストだけで処理に必要な情報がそろうことです。この問題では、スマートフォンアプリがリクエストごとにJWTをAuthorizationヘッダへ付けます。サーバはそのJWTを検証し、そのリクエストの利用者を識別します。
誤解しやすいのは、ステートレスを「サーバは状態を何も持たない」と読むことです。実際には、次の状態は普通に持ちます。
- 利用者情報や健康データを保存するデータベース
- 課金状態
- 認証コードの値、有効期限、失敗回数
- JWTの署名鍵
- 失効リストを使う設計なら、その失効情報
- ログや監査記録
持たないのは、会話を続けるためだけのサーバ側セッション状態を、各API呼出しの前提にしないということです。
また、ステートレスであることは安全性を自動的に高めません。JWTを毎回送れば水平分散しやすくなりますが、JWTの検証を誤れば、誤りも全ノードへ一様に広がります。アーキテクチャ上の性質とセキュリティ上の正しさは別です。
5.設問2(1) ── 4桁コードは平均500秒で当たる
認証APIは、利用者IDとパスワードが合っていれば、メールへ4桁の数字を送ります。その後、利用者IDと4桁コードが一致すればJWTを発行します。コードは生成から10分間有効です。
診断では、1秒に10回の試行が可能でした。平均して何秒で突破できるかを求めます。
計算は「候補数の半分」
4桁の数字は、先頭の0を含めて次の1万通りです。
0000, 0001, 0002, ... , 9999
正解が一様に選ばれているなら、順番に重複なく試す攻撃者が正解へ到達するまでの平均試行回数は、候補数の半分です。
平均試行回数 = 10,000 ÷ 2 = 5,000回
平均時間 = 5,000 ÷ 10回/秒 = 500秒
したがって、空欄bは 500 です。
最大では1,000秒かかりますが、問題が問うのは平均です。そしてコードの有効期間は600秒なので、平均突破時間の500秒より長い。これが「突破される可能性が高い」と判断された理由です。
flowchart LR
accTitle: 4桁認証コードの時間感覚
accDescr: 1万通りを1秒10回で試すと平均5,000回、500秒で当たり、有効期間600秒より短い
A[候補数 10,000通り] -->|平均 10,000 / 2 = 5,000回| B[平均突破時間 500秒]
C[有効期間 600秒] -->|500秒 < 600秒| D[有効期間内に突破可能]
図9: 4桁認証コードの時間感覚。候補数の半分を平均で試すと、有効期間内に当たる。
失効時間だけを短くしても、候補が少なければ負ける
認証コードの強さは、桁数だけでも有効期間だけでも決まりません。
有効期間中に試せる回数
= 1秒当たりの試行回数 × 有効期間
= 10 × 600
= 6,000回
重複しない値を順に試すなら、1万通りの60%を有効期間内に確認できます。失効時間を設けていても、試行回数を制限していなければ十分ではありません。
現行のNIST SP 800-63Bは、帯域外認証で使う短期秘密について少なくとも6桁を求め、64bit未満なら試行回数制限を必須にしています。また、電子メールを帯域外認証に使わないよう求めています4。試験では与えられた4桁・メール送信という仕様の中で解答しますが、実務の新規設計ではその前提自体も見直すべきです。
6.設問2(2) ── alg=noneは「攻撃者に検証方法を選ばせた」問題
問題のJWTは、ヘッダ、ペイロード、署名の三つから成ります。
base64url(header).base64url(payload).base64url(signature)
ヘッダには、署名に使うアルゴリズムとしてRS256が記録されていました。ペイロードには利用者IDや発行時刻、有効期限が入っています。
診断者は、次の二つを変更しました。
- ヘッダの
algをRS256からNONEへ変更する - ペイロードの利用者IDを別の利用者へ変更する
そのJWTを送ると、検証が成功して他人になりすませました。
flowchart LR
accTitle: JWT alg=none の攻撃の流れ
accDescr: 正しいJWTからalgをnoneに変更し、利用者IDを書き換えて通す流れ
A[正しいJWT<br/>alg=RS256<br/>user=user01] -->|ヘッダのalgをnoneへ| B[改ざんJWT<br/>alg=none<br/>user=user02]
B -->|署名検証をスキップ| C[サーバが<br/>user02として受け入れる]
図3: JWT alg=none 攻撃の流れ。攻撃者が検証アルゴリズムを選んでいる。
noneは文字列の綴りミスではない
RFC 7519には、署名も暗号化も持たないJWTとしてalgがnoneの「Unsecured JWT」が定義されています5。したがって、noneという値が仕様上まったく存在しないわけではありません。
問題は、署名付きJWTだけを受け付けるべきAPIが、攻撃者の指定したnoneを受け入れたことです。
脆弱な処理を概念的に書くと、次のようになります。
1. JWTヘッダを読む
2. ヘッダに書かれたalgを見て、検証方法を選ぶ
3. algがnoneなら署名の検証を行わない
4. ペイロードの利用者IDを信用する
攻撃者が制御する入力から、セキュリティの強さそのものを選ばせています。
試験の解答
設問は、修正後のライブラリQが「どのデータに対して、どのような検証を行うか」を、それぞれ20字以内で問います。
解答例は次のとおりです。
| 項目 | 解答の要点 |
|---|---|
| 検証対象のデータ | JWTヘッダ内のalgに指定された値 |
| 検証の内容 | NONEでないことを検証する |
問題文の脆弱性に対する直接の修正としては、これで正解です。
実務では「NONE以外ならよい」にしない
ここは、試験の解答と実務の推奨を分ける必要があります。
RFC 8725は、JWTライブラリが呼出し側に許可アルゴリズムの集合を指定させ、その集合以外を使ってはならないとしています6。つまり、次のような考え方です。
悪い考え方:
token.header.alg != "none" なら受け入れる
良い考え方:
serverConfig.allowedAlgorithms に含まれる場合だけ受け入れる
例: allowedAlgorithms = ["RS256"]
noneだけを拒否しても、別の弱いアルゴリズムや、公開鍵方式と共通鍵方式を取り違えるアルゴリズム混同が残る可能性があります。受け入れる条件を否定形で増やすのではなく、許可する条件を狭く固定するのが原則です。
JWTの検証では、アルゴリズムだけでなく、用途に応じて少なくとも次を確認します。
| 項目 | 確認すること |
|---|---|
| 署名 | 想定した鍵とアルゴリズムで検証できるか |
iss |
信頼する発行者か |
aud |
このAPI向けに発行されたトークンか |
exp |
有効期限内か |
nbf |
利用開始時刻より前ではないか |
subまたは利用者ID |
アプリケーション上の有効な主体か |
| トークン種別 | IDトークンとアクセストークンなどを取り違えていないか |
この問題ではペイロードのキー名がuserですが、実務では標準のsubを使うか、独自クレームの意味を明確に定義します。
flowchart TB
accTitle: 安全なJWT検証と危険なJWT検証
accDescr: 危険な検証はalgに依存し、安全な検証はサーバ側の許可リストを使う
subgraph "危険な検証"
D1[JWTヘッダのalgを読む]
D2[algがnoneなら受け入れる]
D1 --> D2
end
subgraph "安全な検証"
S1[サーバ設定の許可アルゴリズム<br/>例: RS256]
S2[JWTヘッダのalgが<br/>許可リストに含まれるか確認]
S3[署名・iss・aud・expを検証]
S1 --> S2 --> S3
end
図4: 安全な検証と危険な検証。実務では許可するアルゴリズムを狭く固定する。
Base64urlは暗号化ではない
もう一つ、JWTでよく起きる誤解があります。ヘッダとペイロードはbase64urlで表現されますが、これは暗号化ではありません。誰でもデコードして読めます。
署名が保証するのは、正しく検証できた場合に限り、内容が発行後に改ざんされていないことです。秘密にしたい個人情報を、署名付きJWTのペイロードへ入れてよいという意味ではありません。
7.設問2(3) ── 正しいJWTでも、midを変えれば他人を読めた
次は、JWT自体を改ざんしない攻撃です。
利用者APIは、GETまたはPUTでmidという利用者IDを受け取ります。共通モジュールPは、そのmidにひも付く利用者情報をデータベースから取得・更新します。
攻撃の構図は単純です。
JWTの利用者ID: user01 ← 正しく署名されたJWT
リクエストのmid: user02 ← 攻撃者が変更
JWTの署名は正しいので、認証は成功します。しかし、APIはmid=user02をそのまま信用し、user02の情報を返します。
これはOWASP API Security Top 10 2023でいう Broken Object Level Authorization(BOLA) に当たる典型です。利用者が指定したオブジェクトIDを使ってデータへアクセスするとき、毎回そのオブジェクトへの認可を確認する必要があります7。
flowchart LR
accTitle: BOLAの攻撃
accDescr: 正しいJWTを使いながら、リクエストのmidを別の利用者IDに変える
A[攻撃者] -->|JWT: user01<br/>mid: user02| B[利用者API]
B -->|midを信用| C[DBからuser02の情報を返す]
図5: BOLAの攻撃。認証は通るが、認可を確認していない。
設問の解答
表5の下線②は、共通モジュールPの呼出し処理へ追加する処理を40字以内で問います。
解答例は次です。
JWTに含まれる利用者IDがmidの値と一致するかどうかを検証する処理
共通モジュールPで検証する利点は、GETとPUTの両方、そして今後Pを利用する別のAPIにも同じ認可を効かせやすいことです。各画面や各エンドポイントへ同じ比較処理をコピーすると、どこか一つで漏れます。
より安全な設計は、midを受け取らないこと
自分自身の情報だけを取得・更新するAPIなら、クライアントから利用者IDを受け取る必要がありません。
GET /users/me
Authorization: Bearer <JWT>
サーバ側では、検証済みのJWTから主体を取り出します。
principal = validateJwt(request.authorization)
userId = principal.subject
return repository.getUser(userId)
更新も同じです。
principal = validateJwt(request.authorization)
input = validateProfileUpdate(request.body)
repository.updateProfile(
userId = principal.subject,
name = input.name,
age = input.age
)
比較処理は、書けば守れます。しかし、対象IDを外部から受け取らない設計なら、比較処理を書き忘れる種類のバグ自体を減らせます。
管理者が他人の利用者情報を操作する必要があるなら、次のように分けます。
PUT /users/me 一般利用者用
PUT /admin/users/{userId} 管理者用
管理者用には、別の権限、監査ログ、必要なら再認証を要求します。「一般利用者APIに管理者の場合だけ例外を足す」より、認可ポリシーの境界が見えやすくなります。
flowchart LR
accTitle: BOLAの防ぎ方
accDescr: リクエストのmidを使わず、JWTの主体から対象を決めるか照合する
A[利用者] -->|GET /users/me + JWT| B[API]
B -->|JWTのsubを取得| C{midがあれば<br/>subと一致するか}
C -->|一致| D[自分のデータを返す]
C -->|不一致| E[403拒否]
B -->|midなし| F[JWTのsubでDB検索]
図6: BOLAの防ぎ方。midを受け取らないか、JWTの主体と照合する。
認証と認可を一文で区別する
試験でも実務でも、次の言い方が役立ちます。
- 認証: 誰であるか
- 認可: その人が何をしてよいか
JWTの署名検証が成功したのは、「このトークンが表す主体を信用できる」というところまでです。「その主体がuser02を読んでよい」は、別に確認しなければなりません。
8.設問2(4) ── status=paidはプロパティ単位の認可不備
利用者APIの仕様には、更新用パラメータとして次のものが定義されています。
mid 利用者ID
name 名前
age 年齢
ところが診断者は、仕様にない次の値を追加しました。
status=paid
すると、無償利用者のステータスが有償利用者へ変わりました。
問題文によれば、サービスLは受け取ったパラメータを検証せず、すべて共通モジュールPへ渡していました。Pはそのままデータベースを更新できる作りでした。
空欄cの解答は 共通モジュールP です。
flowchart TB
accTitle: Mass Assignment
accDescr: 仕様にないstatus=paidが追加され、内部オブジェクトに丸ごと反映される
A[API仕様<br/>mid / name / age] -->|攻撃者がstatus=paidを追加| B[リクエストボディ]
B -->|自動バインド| C[共通モジュールP]
C -->|DB保存| D[課金状態がpaidに変更]
図7: Mass Assignment。仕様外のプロパティが内部オブジェクトに丸ごと反映される。
BOLAとの違い
前章のmid差替えと、今回のstatus追加は似ていますが、守る粒度が違います。
| 脆弱性 | 攻撃者が変えるもの | 本来確認すべきこと |
|---|---|---|
mid差替え |
対象オブジェクト | この利用者がこの利用者レコードへアクセスしてよいか |
status追加 |
オブジェクト内のプロパティ | この利用者がこの項目を変更してよいか |
OWASP API Security Top 10 2023では、後者を Broken Object Property Level Authorization として扱い、以前のMass Assignmentをこの分類に含めています8。
「JSONをそのままエンティティへ入れる」が危険
脆弱な実装は、概念的には次のようなものです。
entity = repository.find(body.mid)
bindAllProperties(entity, body)
repository.save(entity)
画面にはnameとageしか入力欄がなくても、攻撃者はHTTPリクエストを直接作れます。UIにない項目は、セキュリティ境界ではありません。
安全な実装は、更新可能な項目を明示します。
input = parseExactSchema(body, fields = ["name", "age"])
entity = repository.find(authenticatedUserId)
entity.name = input.name
entity.age = input.age
repository.save(entity)
ここで大切なのは二つです。
- 更新用の入力型に、利用者が変更してよい項目だけを置く
- 仕様外の未知の項目を無視するのではなく、できればエラーとして拒否する
未知の項目を黙って無視すると、攻撃が失敗したことは隠せますが、クライアントの実装ミスや攻撃の兆候を見落とします。互換性上の理由がなければ、厳密なスキーマで拒否した方が調査しやすくなります。
flowchart TB
accTitle: 項目単位の認可
accDescr: 更新用DTOは許可リストだけを持ち、未知のプロパティは拒否する
subgraph "更新用DTO(許可リスト)"
D1["name"]
D2["age"]
end
A[リクエストボディ] -->|スキーマ検証| B{許可された<br/>項目のみか}
B -->|はい| C[エンティティのname/ageを更新]
B -->|いいえ| D[エラーを返す]
E[決済サービス<br/>検証済み通知] -->|専用経路| F[status=paidを更新]
図8: 項目単位の認可。更新可能な項目を許可リストで制限し、課金状態は別経路で変更する。
statusは決済結果からだけ変える
status=paidは、利用者プロフィールの一部ではありません。決済が成功したというサーバ側の事実から導かれる状態です。
利用者のプロフィール更新
-> name / ageだけ変更可能
決済サービスからの検証済み通知
-> paymentIdを照合
-> 重複処理を防止
-> statusをpaidへ変更
同じデータベース列に保存していても、変更する権限と経路は別です。内部エンティティをそのまま外部APIの入力型に使うと、この境界が消えます。
9.設問2(5) ── 総当たり対策は失敗回数を状態として持つ
4桁コードの総当たりに対して、表5の空欄dへ入る処理を30字以内で答えます。しきい値は10です。
解答例は次です。
連続失敗回数がしきい値を超えたらアカウントをロックする処理
ここは、設問1のステートレスと矛盾しません。API呼出しの会話状態をサーバセッションとして持たないことと、セキュリティ判断に必要な失敗回数を永続化することは別です。
flowchart LR
accTitle: 試行回数制限の有無
accDescr: 制限がないと平均500秒で突破されるが、失敗回数制限で攻撃速度を抑えられる
subgraph "制限なし"
A1[1秒に10回試行] -->|約500秒| B1[認証成功]
end
subgraph "制限あり"
A2[失敗10回でロック] -->|攻撃速度を急降下| B2[アカウントロック]
C2[段階的遅延] --> B2
end
図10: 回数制限の有無。失敗回数制限により総当たりを実用的に止められる。
実務では「永久ロック一択」にしない
アカウント単位の回数制限は必要ですが、攻撃者が他人の利用者IDを知っている場合、わざと10回失敗して正規利用者を締め出せます。そこで、実務では次を組み合わせます。
| 制御 | 役割 |
|---|---|
| アカウント単位の失敗回数 | 一つのアカウントへの総当たりを止める |
| 段階的な待ち時間 | 正規利用者の入力ミスを許容しつつ、攻撃速度を落とす |
| 送信元IP・端末・ASNなどの制御 | 多数のアカウントへ少数回ずつ試す攻撃を抑える |
| リスクベース判定 | 普段と異なる地域・端末・速度を強く制限する |
| 利用者への通知 | 攻撃や誤操作に気付けるようにする |
| 安全な回復手順 | ロックを解除する窓口を攻撃経路にしない |
さらに、コードを再送したときに失敗回数を0へ戻してはいけません。攻撃者が再送APIを呼ぶたびに試行枠を復活できるからです。現行NIST SP 800-63Bも、新しい認証秘密を生成しても失敗回数をリセットしないよう求めています4。
認証コードは一度だけ使えるようにする
問題文では有効期限が中心ですが、実務では次も必要です。
- 成功したコードは直ちに無効化する
- 同じコードの再利用を拒否する
- コードそのものをログへ残さない
- コード照合の成否から、利用者の存在有無を推測できない応答にする
- コード送信APIにも回数制限を設ける
短い秘密を使う以上、ランダム生成だけに安全性を任せられません。
flowchart TB
accTitle: 認証コード対策
accDescr: 桁数・失効時間に加え、試行回数制限・再利用拒否・通知などで守る
A[認証コード] --> B[桁数を増やす]
A --> C[有効期限を短くする]
A --> D[試行回数制限]
A --> E[成功後は無効化]
A --> F[再送で失敗回数をリセットしない]
A --> G[コードをログに残さない]
A --> H[送信元単位の制御]
図11: 認証コード対策。桁数と失効時間だけでなく、試行制御と運用を組み合わせる。
10.設問2の四つを一枚で区別する
設問2で混同しやすい論点を、攻撃者が制御した値で整理します。
| 攻撃 | 攻撃者が変えた値 | 信頼してはいけなかった場所 | 根本対策 |
|---|---|---|---|
| JWT改ざん | JWTヘッダのalg、ペイロードの利用者ID |
トークン自身が申告する検証アルゴリズム | 許可アルゴリズムをサーバ側で固定する |
| 他人の情報取得 | リクエストのmid |
クライアントが指定した対象ID | JWTの主体と照合するか、対象IDをJWTから決める |
| 有償利用者への変更 | 仕様外のstatus |
自動バインドされた全プロパティ | 更新可能プロパティを許可リスト化する |
| 4桁コード突破 | otpの候補 |
無制限の認証試行 | 失敗回数制限、遅延、リスク判定を入れる |
「入力値を検証する」で全部をまとめないことが重要です。
algは、暗号処理のポリシーmidは、オブジェクト単位の認可statusは、プロパティ単位の認可otpは、オンライン推測への耐性
同じHTTPリクエストの中にあっても、守る理由が違います。
11.設問3(1) ── 破壊せずに外部コード実行を確かめる
サービス開始後、広く使われるオープンソースライブラリHに重大な脆弱性Vが公表されます。問題文の流れは、次のとおりです。
- 攻撃者が、JNDI Lookupを含む文字列をHTTPヘッダへ入れて送る
- 攻撃対象サーバがその値をログへ出力する
- 脆弱なライブラリがJNDI Lookupを評価し、攻撃用LDAPサーバへ問い合わせる
- LDAPレスポンスが攻撃用HTTPサーバのURLを返す
- 攻撃対象サーバがクラスファイルを取得し、コマンドを実行する
これは、固有名を伏せた Log4Shell(CVE-2021-44228)型の攻撃 と読めます。Apacheの説明でも、攻撃者がログメッセージやパラメータを制御できると、LDAPサーバから読み込んだ任意コードを実行できる脆弱性として説明されています9。
flowchart LR
accTitle: Log4Shell型脆弱性の確認フロー
accDescr: 無害なコールバックでJNDIから外部コード実行までの連鎖が通るか確認する
A[攻撃者] -->|x-api-versionに<br/>jndi:ldap://...を注入| B[脆弱なサーバ]
B --> C[ログ処理]
C -->|JNDI Lookup| D[悪用LDAPサーバ]
D -->|HTTP URL応答| E[悪用HTTPサーバ<br/>index.html]
E -->|GETを記録| F[テストサーバ<br/>アクセスログ]
F -->|到達確認| G[脆弱性を確認]
図12: Log4Shell型脆弱性の確認フロー。破壊的な命令ではなく、HTTPアクセスの記録で到達を確認する。
検証コードは、無害なHTTPアクセスだけを起こす
G社は、システムに影響を与えない検証コードを実行し、外部から脆弱性Vを悪用できるか確認します。検証コードが行う命令は、テストサーバのindex.htmlを取得するだけです。
設問3(1)は、テストサーバへ何を実装すれば、コマンドが実行されたと確認できるかを問います。
解答例は次です。
テストサーバのindex.htmlへのアクセスを記録し、確認する仕組み
Webサーバのアクセスログに、攻撃対象サーバからのGETが残れば、少なくとも次の連鎖が通ったことを確認できます。
外部HTTPリクエスト
-> ログ処理
-> JNDI Lookup
-> LDAP応答
-> クラス取得
-> 検証コマンド実行
-> テストサーバへのHTTPアクセス
なぜ「画面に文字を出す」では足りないのか
攻撃対象はサーバです。利用者のブラウザ画面に変化が出るとは限りません。また、脆弱性が存在しても、途中の外向き通信がファイアウォールで止まる場合があります。
テストサーバ側でアクセスを記録すれば、攻撃対象サーバから外部へ到達したという観測可能な証拠になります。
実務で同種の検証を行うときは、必ず次を守ります。
- 対象システムの所有者から明示的な承認を得る
- 本番への影響がない、または許容できる検証方法にする
- 書込み・削除・設定変更などの破壊的な命令を使わない
- 検証用ドメインやサーバを自社で管理する
- 検証時刻、送信元、対象、期待するコールバックを記録する
- 検証後に一時的なLDAP・HTTPサーバや資格情報を撤去する
「任意コード実行を確認する」ことと、「任意の危険なコードを実行する」ことは同じではありません。目的を満たす最小の副作用にします。
12.設問3(2)(3) ── WAFはHTTPヘッダを検査する
サービスNのWAFは、検査対象としてGET、POST、PUT、ANY、Header、COOKIE、Multipartを選べます。
攻撃コードはx-api-versionというHTTPヘッダの値に入ります。したがって、表6の空欄eとfは、どちらも Header です。
本文に書いてある場所を、そのままWAFの検査対象へ対応させる
ここは一般知識より、問題文のデータフローを読む問題です。
攻撃文字列の置き場所:
x-api-versionヘッダ
|
v
WAFの検査対象:
Header
GETパラメータでもPOST本文でもありません。WAFの機能一覧を見て「攻撃っぽいからANY」と選ぶのではなく、問題文で攻撃者が値を入れた場所を答えます。
大文字・小文字の入替えへ対応する
最初の案は、概念的には次のルールでした。
Header \Wjndi\W 遮断
Header \Wldap\W 遮断
しかし、jNdIのように大文字・小文字を入れ替えると、単純な小文字だけのパターンを回避できます。
設問3(3)の解答例は、次のいずれかです。
\W[jJ][nN][dD][iI]\W
\W(j|J)(n|N)(d|D)(i|I)\W
問題冊子ではバックスラッシュが日本語環境の字形で円記号に見える場合がありますが、正規表現としては\Wです。\Wは英数字とアンダースコア以外の文字に一致します。JNDI Lookupの構文では、jndiの前後に${や:などの非単語文字が現れるため、それを含めて見ています。
同じ考え方でldap側も大文字・小文字を無視する形へできます。
\W[lL][dD][aA][pP]\W
この正規表現を「完全なLog4Shell対策」と考えない
試験は、問題文に示された回避方法へ対応する正規表現を答えるものです。実際の攻撃では、文字列の分割、別のLookup、エンコード、別プロトコルなど、シグネチャだけでは網羅しにくい変形があり得ます。
したがって、実務での位置付けは次です。
- 今判明している攻撃パターンをWAFで暫定的に止める
- 影響を受けるライブラリが本当に含まれるか調べる
- 外向きLDAP・RMI・不要なHTTP通信を制限する
- 修正版へ更新する
- 更新後もログを確認し、侵害の有無を調査する
WAFは、修正版が出るまでの時間を稼ぐ層です。
flowchart TB
accTitle: WAFの位置づけ
accDescr: WAFは暫定緩和の層で、根本対策はライブラリの修正版へ更新すること
A[重大な脆弱性公表] --> B[影響確認]
B --> C[暫定緩和]
C -->|WAFルール<br/>検知/遮断| D[攻撃パターンを一時的に止める]
C -->|外向き通信制限| E[悪用経路を塞ぐ]
D --> F[修正版ライブラリへ更新]
E --> F
F --> G[事後確認と再発防止]
図13: WAFの位置づけ。WAFは修正版が出るまでの時間稼ぎであり、根本対策は更新である。
13.設問3(4) ── 最初に「検知」を使う理由
変更後のWAFルールについて、登録セキスペのZ氏は、本番運用開始後の一定期間は動作を「遮断」ではなく「検知」にするよう助言します。
設問は、検知にする利点と、被害を最小化するために実施すべき内容を、それぞれ25字以内で問います。
解答例は次です。
| 項目 | 解答の要点 |
|---|---|
| 利点 | 誤検知による遮断を防ぐことができる |
| 実施すべき内容 | アラートを受信したら攻撃かどうかを精査する |
検知モードは「何もしないモード」ではない
検知モードでは、ルールに一致した通信を通しつつ、ログへ記録してアラートを出します。正常なAPI呼出しの中に偶然jndiやldapという文字列が入る場合でも、いきなり業務を止めません。
その代わり、運用側には次が必要です。
アラート受信
|
v
対象リクエストを確認
|
+-- 正常通信 -> ルールを狭める、例外条件を検討
|
+-- 攻撃 -> 対象を隔離、ログ保全、影響調査、遮断へ
アラートを誰も見ないなら、検知モードには防御効果がありません。検知は、観測して判断する運用と一組です。
検知から遮断へ移す流れ
一般的な導入手順は次です。
- 検知モードで実トラフィックに当てる
- 誤検知と正検知を分類する
- 対象ヘッダ、パス、API、文字境界などを調整する
- 正常通信への影響が許容できることを確認する
- 遮断モードへ移す
- 遮断件数と業務影響を監視する
ただし、これは平時の原則です。脆弱性が重大で、現に悪用され、代替手段がない場合は、誤検知による停止より侵害の被害が大きいと判断して、最初から遮断することもあります。試験の状況では、サービスを今までどおり利用できるか確認するため、まず検知を選んでいます。
flowchart LR
accTitle: WAFの検知から遮断へ
accDescr: 検知モードでアラートを観測し、誤検知を調整してから遮断モードへ移行する
A[検知モード] -->|実トラフィック| B[アラート発生]
B --> C{攻撃か<br/>誤検知か}
C -->|誤検知| D[ルールを調整]
D --> A
C -->|攻撃| E[遮断モードへ]
E --> F[遮断件数と業務影響を監視]
図14: 検知から遮断へ。まず観測・調整し、影響が許容できることを確認して遮断へ移す。
14.WAFは暫定対策、更新が根本対策
問題文では、ライブラリHの公式サイトに修正版も暫定対策もまだなく、クラウド事業者の網羅的なWAFルールも最大72時間かかる状況でした。だからG社は、自分たちで影響を確認し、判明しているパターンだけでも一時的に防ぎます。
この順番は、インシデント対応の基本形です。
| 段階 | 目的 | この問題での対応 |
|---|---|---|
| 影響確認 | 自社が本当に危険かを判断する | 無害なコールバックで外部悪用の可否を確認 |
| 暫定緩和 | 修正までの時間を稼ぐ | WAFルール、検知・遮断、外向き通信制限 |
| 根本修正 | 脆弱な原因を除去する | 修正版ライブラリへ更新 |
| 事後確認 | 既に悪用されていないか調べる | WAF・アプリ・DNS・プロキシなどのログ調査 |
| 再発防止 | 次回の判断を速くする | 依存関係の棚卸し、SBOM、更新手順、連絡経路 |
「使っているか分からない」が最大の遅延になる
問題文では、G社がF社へライブラリHを使っているか問い合わせても、詳細な構成分析が必要で回答に時間がかかるとされています。
実務では、重大な脆弱性の公表後に初めてJARファイルを探し始めると、対応が遅れます。少なくとも次を平時から持っておくべきです。
- 直接依存と推移的依存の一覧
- 配布物に実際に含まれるコンポーネントとバージョン
- どのサービス・コンテナ・端末へ展開されているか
- 依存ライブラリを更新して再ビルド・再配布する手順
- 緊急変更を承認する連絡経路
- 外向き通信の許可先と、止めたときの影響
- ログの保存場所と検索方法
SBOMは目的ではありません。「この脆弱性は、どの実行中システムへ影響するか」を短時間で答えるための索引です。
更新しただけで調査を終えない
脆弱性の公表前後に既に攻撃を受けていた可能性があります。修正版へ更新して今後の悪用を止めても、侵害済みの資格情報や設置されたバックドアまでは消えません。
Log4Shell型なら、少なくとも次の観点を調べます。
- JNDIやLDAPを示す不審な文字列を含むHTTPリクエスト
- アプリケーションサーバから外部LDAP・RMI・HTTPへの通信
- 通常と異なる子プロセスの起動
- 不審なJAR、class、スクリプト、実行ファイルの作成
- クラウド資格情報や環境変数へのアクセス
- 更新前後の認証・権限変更・外部送信
WAFログだけで「攻撃されていない」と断定しないことが重要です。WAFを通らない内部経路や、過去に保存されていないログがあるからです。
15.試験で点を取りやすくする読み方
この問題は、知識問題というより、仕様と実装の差分を読む問題です。
15.1 表の「仕様」と「実装」を分ける
statusの問題では、API仕様にない値が実装では通っています。
仕様:
mid / name / age
実装:
受け取ったパラメータをすべてPへ送る
この差分が見えれば、空欄cが共通モジュールPだと分かります。
15.2 攻撃者が変えた値に線を引く
各攻撃で変えられた値は次です。
- JWTヘッダの
alg - JWTペイロードの利用者ID
- APIパラメータの
mid - 仕様外の
status - 認証APIの
otp - HTTPヘッダの
x-api-version
設問は、ほぼすべて「その値がどこで検証されるべきか」を聞いています。
15.3 解答は問題文の用語へ戻す
実務では「BOLA」「Mass Assignment」「rate limiting」と呼べます。しかし、設問が求めるのは、問題文の構成に合わせた具体的な処理です。
悪い例:
認可を適切に行う。
良い例:
JWTに含まれる利用者IDがmidの値と一致するか検証する。
悪い例:
ブルートフォース対策をする。
良い例:
連続失敗回数がしきい値を超えたらアカウントをロックする。
抽象名を知っているだけでは、字数内で採点可能な答えになりません。
15.4 WAFは「どこに入ったか」を追う
WAFの検査対象は、攻撃種類から推測するのではなく、攻撃文字列の格納場所から決めます。
x-api-versionヘッダに入れた
↓
検査対象はHeader
採点講評で設問3(1)の正答率がやや低かったのも、図6の攻撃の流れに合わない答えが多かったためです。攻撃手順を矢印で書き直すだけでも、何を観測すべきかが見えます。
16.実務のAPIレビューで使えるチェックリスト
この問題を、実際の設計・コードレビューへ持ち帰るためのチェックリストです。
JWT検証
- 許可する署名アルゴリズムをサーバ設定で固定している
noneや想定外のアルゴリズムを拒否する- 署名、
iss、aud、exp、nbfを用途に応じて検証する - IDトークン、アクセストークン、リフレッシュトークンを取り違えない
- 鍵のローテーションと失効時の手順がある
- JWTペイロードへ秘匿すべき情報を入れていない
オブジェクト単位の認可
- リクエスト内のIDを変えたとき、他人のデータへ到達できない
- 一覧、詳細、更新、削除、ダウンロードのすべてで認可している
- 認可は画面ではなく、データへ到達する共通層で実施している
- 自分専用APIでは、対象IDをトークンから導出できないか検討した
- 管理者用の操作は一般利用者用APIとポリシーを分けている
プロパティ単位の認可
- 外部入力型とデータベースエンティティを分けている
- 更新可能な項目を許可リストで列挙している
- 仕様外のプロパティを拒否または監査している
- 権限、課金、承認、所有者などの状態を利用者入力から変更できない
- レスポンスにも不要な機密プロパティを含めていない
認証試行
- アカウント単位の失敗回数制限がある
- 段階的遅延や送信元単位の制御がある
- コード再発行で失敗回数がリセットされない
- 認証コードは一度だけ使える
- 認証コードやパスワードをログへ残さない
- ロック解除・回復手順が別の弱い認証経路になっていない
重大な依存ライブラリ脆弱性
- 実行中のサービスと依存バージョンを対応付けられる
- 無害な方法で影響を検証する手順がある
- WAFや外向き通信制限などの暫定策を適用できる
- 検知アラートを担当者が確認する運用がある
- 修正版へ更新する緊急リリース経路がある
- 更新前に悪用された可能性をログから調査する
17.この問題から見える、共通部品の二面性
この問題では、JWT管理ライブラリQと共通モジュールPという二つの共通部品が登場します。
共通部品には大きな利点があります。
- 一か所を直せば、利用する全APIへ修正を反映できる
- 認可や検証の実装を各機能へ重複させずに済む
- テスト対象を集約できる
- ログや監査の形式を統一できる
一方で、誤りも全体へ広がります。
- ライブラリQが
alg=noneを受け入れると、JWTを使う全APIが危険になる - 共通モジュールPが任意の
midやstatusを受け入れると、GETとPUTの両方が危険になる - 脆弱なライブラリHが基盤で使われると、HTTPヘッダをログに出す複数経路が攻撃面になる
したがって、共通化するべきなのは単なるデータアクセスではありません。セキュリティ不変条件を共通化し、その共通部品を単体で厳しく検証する必要があります。
例えば、Pの契約を次のようにします。
P.getOwnUser(authenticatedSubject)
P.updateOwnProfile(authenticatedSubject, ProfileUpdate{name, age})
次のような低水準APIを、一般の呼出し側へそのまま公開しない方が安全です。
P.getUser(arbitraryMid)
P.updateUser(arbitraryMap)
後者が必要なのは管理処理など限定された経路だけです。低水準の自由度を全APIへ配ると、各呼出し側が毎回正しく使うことを期待する設計になります。
18.まとめ
令和6年度 春期 午後 問1は、APIセキュリティの論点を一つずつ分離して読む問題です。
JWTを使っていることは、安全な認証を意味しません。署名アルゴリズムを攻撃者に選ばせれば、利用者IDを書き換えられます。
JWTの署名が正しいことは、正しい認可を意味しません。リクエストのmidを信用すれば、正規利用者が他人の情報へアクセスできます。
自分のオブジェクトを更新できることは、すべてのプロパティを変更してよいことを意味しません。statusのような内部状態を自動バインドすれば、権限や課金状態を書き換えられます。
認証コードに有効期限があることは、総当たりに強いことを意味しません。候補数と試行速度を計算し、失敗回数を制限する必要があります。
WAFにルールを入れることは、脆弱性を修正したことを意味しません。検知と遮断で時間を稼ぎ、影響を確認し、最終的にはライブラリを更新します。
flowchart TB
accTitle: 脆弱性と対策の対応表
accDescr: 各脆弱性とそれに対する信頼境界、対策を対応付ける
A[JWT改ざん] -->|トークン検証| B[許可アルゴリズムを固定]
C[mid差替え] -->|オブジェクト単位の認可| D[JWT主体と照合/mid不要]
E[status=paid] -->|プロパティ単位の認可| F[更新DTOを許可リスト化]
G[4桁コード総当たり] -->|認証試行制御| H[失敗回数制限・遅延]
I[Log4Shell型脆弱性] -->|入力から実行| J[ライブラリ更新/WAF]
図15: 脆弱性と対策対応表。破られた境界ごとに対策を分ける。
この問題を貫く原則は一つです。
一つ前の検証に成功したことを、次の信頼境界を省略する理由にしない。
シリーズの前の記事では、令和5年秋 午後問1の格納型XSSと、令和5年秋 午後問2の来客用Wi-Fiからの情報持出しを解説しています。Webサイト全体の確認観点は、IPA「安全なウェブサイトの作り方」をチェックリストとして使うも参照してください。
flowchart TB
accTitle: 最終まとめ
accDescr: 一つ前の検証に成功しても、次の信頼境界を省略しないことを示す
A[認証成功] --> B[JWT署名検証]
B --> C[オブジェクト単位の認可]
C --> D[プロパティ単位の認可]
D --> E[試行回数制限]
E --> F[入力から実行への境界]
F --> G[WAF/ライブラリ更新]
図16: 最終まとめ。信頼境界は段階的に確認し、一つを省略してはならない。
参考リンク
-
IPA, 令和6年度 春期 情報処理安全確保支援士試験 午後 問題冊子。本記事が扱う問題文です。 ↩
-
IPA, 令和6年度 春期 情報処理安全確保支援士試験 午後 解答例。各設問の公式解答例です。 ↩
-
IPA, 令和6年度 春期 情報処理安全確保支援士試験 午後 採点講評。正答率と誤答傾向の説明です。 ↩
-
NIST, SP 800-63B: Authentication and Authenticator Management。短期秘密の桁数、試行回数制限、再発行時の失敗回数、電子メールを帯域外認証に使わないことなどを示しています。 ↩ ↩2
-
RFC Editor, RFC 7519: JSON Web Token (JWT)。Unsecured JWTと
alg=noneを含むJWTの仕様です。 ↩ -
RFC Editor, RFC 8725: JSON Web Token Best Current Practices。許可アルゴリズムの固定、発行者・主体・audienceの検証などを定めるBCPです。 ↩
-
OWASP, API1:2023 Broken Object Level Authorization。利用者が指定するオブジェクトIDごとに認可を確認する必要性を説明しています。 ↩
-
OWASP, API3:2023 Broken Object Property Level Authorization。Mass Assignmentを含む、プロパティ単位の認可不備と対策を説明しています。 ↩
-
Apache Logging Services, Security。CVE-2021-44228の影響、JNDIとLDAPを介したコード実行、修正版を説明しています。 ↩
関連する記事
同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。
情報処理安全確保支援士 令和5年秋 午後問1解説 ── 16件のレビューが2件しか表示されない格納型XSS
情報処理安全確保支援士試験 令和5年秋 午後問1を題材に、格納型XSSの攻撃の流れを解説します。文字数制限が分割投稿で破られた理由、セッションIDが外部に送られず画像として持ち出された経路、そこで効いた対策を整理します。
情報処理安全確保支援士 令和5年秋 午後問2解説 ── 来客用Wi-Fiから持ち出されるファイル
情報処理安全確保支援士試験 令和5年秋 午後問2を題材に、USBメモリを塞いだ会社が来客用Wi-Fiからファイルを持ち出される経路を解説します。サーバ証明書の検証とHSTS、MACアドレスフィルタリングの限界、EAP-TLSとTPMによる対策を整理します。
ホームページの発注側も知っておきたい ── IPA「安全なウェブサイトの作り方」をチェックリストとして使う
会社のホームページのセキュリティは何を基準に確認すべきか。IPA「安全なウェブサイトの作り方」が取り上げる11の脆弱性と対策を、発注側・運営側にも分かる言葉で解説し、発注・検収・運用での使い方を紹介します。
情報セキュリティ10大脅威 2026 ── ランキングの眺め方と、中小企業が本当に対策すべきもの
IPA「情報セキュリティ10大脅威2026」では、ランサム攻撃が11年連続の1位、サプライチェーン攻撃が2位、初選出の「AIの利用をめぐるサイバーリスク」が3位に入りました。組織編トップ10の内容と、中小企業がどの脅威を自分事として対策すべきかを解説します。
中小企業のセキュリティ対策、何から始めるか ── IPA「中小企業の情報セキュリティ対策ガイドライン」第4.0版の歩き方
中小企業のセキュリティ対策は何から始めるべきか。IPA「中小企業の情報セキュリティ対策ガイドライン」第4.0版をもとに、情報セキュリティ6か条、5分でできる自社診断、SECURITY ACTIONまで段階的に解説します。
関連トピック
このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。
Windows技術トピック
Windows 開発、不具合調査、既存資産活用の技術トピックをまとめた入口です。
このテーマがつながるサービス
この記事は次のサービスページにつながります。近い入口からご覧ください。
HP制作
会員APIやスマートフォン連携では、JWT検証、オブジェクト単位の認可、更新可能プロパティの制限がそのままWebシステムの安全性に直結するためです。
技術相談・設計レビュー
既存APIの認可漏れ、依存ライブラリの影響範囲、WAFの暫定ルールを設計レビューで洗い出す作業は技術相談の範囲だからです。
よくある質問
この記事のテーマについて、相談時によくある質問をまとめています。
- JWTの署名検証に成功したのに、なぜ他人になりすませるのですか。
- この問題では、JWT管理ライブラリがJWTヘッダのalgを攻撃者の指定どおりに受け入れ、alg=noneのJWTを署名なしで正しいものとして扱っていました。したがって、ペイロードの利用者IDを書き換えても検証に成功します。試験の解答は、検証対象をJWTヘッダのalgとし、その値がNONEでないことを確認する、です。ただし実務ではNONEだけを拒否するのでは不十分です。サーバ側の設定で利用を許可するアルゴリズムをRS256などに固定し、トークンが申告したアルゴリズムをそのまま選択に使わないようにします。さらにissuer、audience、有効期限、subjectなども用途に応じて検証します。
- JWT内の利用者IDとリクエストのmidを比較すれば、認可対策として十分ですか。
- この問題の解答としては十分です。共通モジュールPで、JWTに含まれる利用者IDとmidが一致するかを検証すれば、他人のmidを指定する攻撃を止められます。ただし自分自身の情報だけを扱うAPIなら、実務ではmidをクライアントから受け取らず、検証済みJWTのsubjectから利用者IDを決める設計の方が安全です。例えばGET /users/meやPUT /users/meとすれば、比較処理の実装漏れそのものを起こしにくくできます。管理者が他人を操作するAPIは別のエンドポイントと認可ポリシーに分けます。
- statusを追加する攻撃は、なぜ通常の入力値検証だけでは防げないのですか。
- nameの長さやageの範囲を検証しても、そもそも受け取るべきでないstatusを自動バインドして内部オブジェクトへ渡していれば防げないからです。問題は値の形式ではなく、そのプロパティを利用者が変更してよいかというプロパティ単位の認可です。更新用の入力型にはnameとageだけを定義し、未知のプロパティは拒否します。課金状態は決済サービスの成功結果など、サーバが信頼できるイベントだけから変更する必要があります。
- 4桁の認証コードは10分で失効するのに、なぜ危険なのですか。
- 0000から9999までの候補は1万通りしかなく、1秒に10回試せると平均5,000回、つまり500秒で当たるからです。有効期間の10分は600秒なので、重複しない候補を順に試せば有効期間内に6,000通りを確認できます。失効時間だけでは総当たりを止められません。候補数、試行速度、試行回数上限を一緒に設計する必要があります。
- 設問の対策はアカウントロックですが、実務でも即時ロックだけでよいですか。
- いいえ。問題の空欄には、連続失敗回数がしきい値を超えたらアカウントをロックする処理、が入りますが、固定的な永久ロックだけでは攻撃者が他人のアカウントを意図的にロックするサービス妨害を起こせます。実務ではアカウント単位の失敗回数、段階的な待ち時間、送信元や端末のリスク判定、通知、回復手順を組み合わせます。新しいコードを発行しても失敗回数をゼロへ戻さないことも重要です。
- WAFを遮断ではなく検知にする意味は何ですか。
- 正常な文字列を誤って攻撃と判定したときも、業務通信を止めずに済むことです。問題の解答では利点が誤検知による遮断を防げること、実施すべき内容がアラートを受信したら攻撃かどうかを精査することです。検知モードは放置するための設定ではありません。ログを確認して誤検知を除き、ルールを調整し、遮断へ移すための観測期間として使います。既知の重大脆弱性が実際に悪用されている緊急時には、可用性リスクと比較して先に遮断する判断もあり得ます。
- この問題のライブラリHはLog4jですか。
- 問題文は製品名を伏せていますが、JNDI Lookup、LDAPサーバ、HTTPサーバからのクラス取得、HTTPヘッダに埋め込まれた文字列、CVSS v3.1の高い基本値という攻撃の流れは、Log4Shellとして知られるCVE-2021-44228を抽象化したものと読むのが自然です。本記事ではその対応関係を説明しますが、試験では固有名を答える必要はありません。与えられた攻撃手順とWAF仕様から解答できます。
- この問題から実務に持ち帰るべきことは何ですか。
- 認証に成功したこと、JWTが改ざんされていないこと、対象オブジェクトへアクセスしてよいこと、対象プロパティを変更してよいことは、すべて別の確認だという点です。加えて、短い認証コードには試行回数制限が必要であり、重大なライブラリ脆弱性では影響確認、暫定防御、根本修正を並行して進めます。共通部品へ認可を集約すること、入力スキーマを許可リストにすること、JWTの検証条件をサーバ側で固定すること、依存ライブラリを把握して更新できる状態にすることが実務上の中心です。