認可・アクセス制御とRBAC・ABAC・IDOR・BOLA
請求書サービスapp.example.comの利用者アリスが、自分の請求書4101を閲覧できるとします。URLのIDを他社の5201へ変えたら何が起きるべきでしょうか。認証、認可、RBAC、ABAC、IDOR・BOLA、水平・垂直の権限昇格を、APIの入力とデータ取得条件まで追います。以下の企業、ID、時刻、ログは架空です。
読む順序は、主体と権限→APIごとの判断→脆弱な実装と防御→ログ・復旧→演習です。科目B(午後)では『ログイン済みだから許可』『IDが推測しにくいから安全』という答えを避け、誰がどのオブジェクトに何をしてよいかを確認します。
1. 認証された人と、許可された操作は別
用語 | このサービスでの意味 |
|---|---|
認証 | リクエストがアリスの有効なセッションに属することを確認する。認証に成功しても、請求書5201の閲覧・編集権限までは決まらない。 |
認可・アクセス制御 | 利用者、操作、対象、組織・状態などの条件から許可・拒否を決める。読み取りだけでなく更新、削除、エクスポートもAPIごとに判定する。 |
RBAC | 役割に権限を割り当てる方式。例ではviewerは請求書閲覧、editorは請求書編集、tenant-adminは所属企業の管理を担う。役割だけで他社請求書へのアクセスを許さない。 |
ABAC | 利用者・対象・環境の属性で判定する方式。tenant_id、所有者、請求書の承認状態、操作時刻などが条件になる。この例では同じeditorでも所属企業と対象状態で許可が変わる。 |
IDOR / BOLA | クライアントが渡す対象IDを変えるなどして、本来アクセスできないオブジェクトへ到達する欠陥。BOLAはAPIのオブジェクト単位の認可不備を指す。整数IDでもUUIDでも検査は必要。 |
水平の権限昇格 | 同程度の権限を持つ別人・別企業のデータへ越境する。アリスが同じviewerのボブ、または企業Bの請求書5201を読む例。 |
垂直の権限昇格 | 一般利用者が管理者限定の操作を実行する。viewerのアリスが企業Aの請求書を承認・削除する例。 |
企業Aのtenant_idは10、企業Bは20です。アリスは企業Aのviewer、請求書4101は企業A、5201は企業Bに属します。ボブは企業Aのeditorで、請求書4102の担当者です。内部DBのIDはintegerとし、利用者がURLへ書いたIDを認可の根拠にしません。
- 1. Cookieと対象IDを送る
- 2. 操作を要求する
- 3. 所属企業を確認する
- 4. 対象の属性を照合する
セッションから主体を取り出し、対象と操作をDBの信頼できる属性で照合する。
図の二つのAPIノードは同じサービス内の段階です。ブラウザが送る`tenant_id=10`や`role=admin`は攻撃者が変更できる入力として扱います。セッションに結び付いた利用者IDを取得し、DBに保存された所属・役割・対象の属性を確認します。
2. 判定を主体・操作・対象・環境に分解する
判定要素 | 正常例と危険な読み違い |
|---|---|
主体(subject) | アリスのuser_idと有効なtenant_id、役割をサーバ側で取得する。URLやJSON本文のuser_idを本人として採用しない。 |
操作(action) | `GET /invoices/4101`の閲覧と`POST /invoices/4101/approve`の承認は別権限。GETの成功をPOSTの許可へ流用しない。 |
対象(object) | 請求書4101のtenant_idと所有者、状態をDBから読む。数値IDの連番か否かはアクセス制御の代わりにならない。 |
環境(environment) | 契約の有効期間、申請の承認状態、アクセス時刻など、必要な条件をサーバが確認する。IPだけを本人確認に使わない。 |
決定(decision) | 全条件が満たされれば許可し、条件が欠けるか判定できなければ拒否する。判定したポリシー版を監査に残す。 |
RBACだけなら『アリスはviewerだから閲覧可能』までしか分かりません。対象が企業Aの4101であることを別に確認します。ABACの`tenant_id`条件を使えば企業Bの5201を拒否できますが、所属情報や対象属性がクライアント改ざん可能な値なら防御になりません。
3. APIごとの正常・異常な要求
要求 | 期待する結果と根拠 |
|---|---|
Alice GET /invoices/4101 | 許可。認証済み、企業Aに属する対象、viewerの閲覧権限がそろう。 |
Alice GET /invoices/5201 | 拒否。企業Bの対象であり、同じ閲覧APIでも所属企業が違う。水平の越境を防ぐ。 |
Alice POST /invoices/4101/approve | 拒否。企業Aの対象でもviewerには承認権限がない。垂直の昇格を防ぐ。 |
Bob PATCH /invoices/4102 | 企業Aのeditorで担当者という条件を満たし、状態が編集可能なら許可。editorという役割だけでは全請求書の編集を許さない。 |
Alice GET /invoices?tenant_id=20 | 要求中のtenant_idを信頼せず、サーバ側の所属企業で一覧を絞る。詳細APIだけでなく一覧・検索・件数も漏えい対象。 |
脆弱な実装は、`SELECT * FROM invoices WHERE id = :id`で対象を取得した後、ログイン済みかだけを確認します。これではアリスが5201を読む可能性があります。改善例は、まずセッションの主体を確定し、`WHERE id = :id AND tenant_id = :trusted_tenant`で対象を絞り、さらに操作に必要な役割・所有者・状態を判定します。
SQLの条件にtenant_idを入れるのは有効ですが、それだけが唯一の実装ではありません。共通の認可サービスで判定する場合も、全APIから同じ方針を呼び、取得と更新の間に対象の所属や状態が変わる競合を考慮します。更新は条件付きUPDATEやトランザクションで再確認し、取得時の古い許可だけで更新しません。
14:00:00 user=alice role=viewer tenant=10
method=GET path=/invoices/4101 object_tenant=10
policy=invoice.read:v3 decision=allow
14:00:10 user=alice role=viewer tenant=10
method=GET path=/invoices/5201 object_tenant=20
policy=invoice.read:v3 decision=deny reason=tenant_mismatch
14:00:20 user=alice role=viewer tenant=10
method=POST path=/invoices/4101/approve
policy=invoice.approve:v3 decision=deny reason=role上記は架空の監査ログです。`decision=deny`は当該APIが拒否したことを示しますが、別のダウンロードAPIや非同期ジョブから同じ対象に到達できない保証ではありません。全ての経路を棚卸しします。ログに請求書本文や秘密のセッション値を残す必要はありません。
4. IDOR・BOLAが成立する経路を洗い出す
詳細閲覧:URLの請求書IDだけで検索し、所属企業を確認しない。典型的なBOLA。
編集・削除:閲覧APIでは認可するが、PATCHやDELETEでは省略する。read許可とwrite許可は別。
一覧・検索:詳細APIは守っても、一覧や件数、CSV出力、集計、サジェストで他社データが漏れる。
入れ子のID:`/customers/10/invoices/5201`で親のcustomerだけ確認し、子の請求書が本当に所属するか確認しない。
非同期ジョブ:作成時に認可せず、ワーカーが送られた請求書IDを信用してエクスポートする。
添付・署名URL:本体の認可後に発行したURLが長期間・広範囲で有効になり、権限変更後もファイルが読める。
別の種類として、一般利用者が管理者API自体を実行できるなら、対象IDの問題に加えて機能レベルの認可不備です。OWASP API Security Top 10ではBOLAとBFLAを区別します。実務では同じインシデントで両方起こり得るため、APIの実行権限と対象オブジェクトの権限を二段階で確認します。
5. 誤設定・権限変更・例外処理
状況 | 対応と確認 |
|---|---|
企業Aの管理者が退職 | 役割を剥奪し、既存セッションとキャッシュの権限を更新する。認可結果を長くキャッシュすると、剥奪後も旧権限が残り得る。 |
請求書を別企業へ移管 | 移管前後のtenant_idを原子的に更新し、旧所属の一覧、ダウンロード、検索インデックス、共有URLを再評価する。 |
緊急の代理操作 | 期限・対象・承認者を限定し、代理操作として監査に残す。恒久的な全件admin付与で代用しない。 |
DBまたは認可サービス障害 | 判定できない場合は拒否する。可用性の例外が必要なら事前に承認された限定手順を使い、事後監査する。 |
エラー応答 | 403か404を返す方針は情報漏えいと運用要件で決める。どちらでも実際のDBアクセスは必ず拒否し、本文や存在情報の差を最小化する。 |
APIのルート名が変わったとき、旧ルート、GraphQLフィールド、管理画面の内部API、バッチ用エンドポイントにも同じルールがあるかを確認します。フロント画面のボタンを隠すだけでは、HTTP要求を直接送る攻撃者を止められません。認可はサーバ側で毎回行います。
6. 調査と復旧の順序
疑わしいID変更要求を受けたら、user_id、tenant_id、対象ID、API、操作、判定、結果時刻を保全する。拒否ログだけでなく、成功した応答・ダウンロード・エクスポート履歴を調べる。
影響した全APIを確認し、対象をサーバ側の信頼できる属性で絞り、役割・所有者・状態を操作別に判定する。機能レベルとオブジェクトレベルの両方を検証する。
正規利用者の操作を壊さないよう、企業A・B、viewer・editor・admin、一覧・詳細・更新・削除・添付を組み合わせたテストを行う。別企業・別所有者の拒否も確かめる。
漏えいがあれば対象データ、利用者、期間、二次利用の可能性を評価し、権限剥奪、共有URL失効、必要な通知を行う。修正後は同じリクエストで拒否されることと監査ログが残ることを確認する。
`decision=allow`のログだけでは、レスポンスが実際に届いたか、本文のどの項目が返されたか分かりません。APIゲートウェイの応答コード、ダウンロード量、オブジェクトアクセスログ、非同期ジョブの完了を照合します。アクセス権の変更前後で時刻とキャッシュ状態を揃えることも重要です。
6-1. オブジェクト全体と項目ごとの権限
請求書4101の閲覧が許可されても、振込先口座や社内承認メモまで返してよいとは限りません。APIレスポンスを役割ごとに組み立て、不要な項目をそもそも選択しない設計にします。フロント画面で非表示にするだけでは、ネットワーク応答やCSVに値が残ります。
利用者・操作 | 請求書4101の項目別判断例 |
|---|---|
Alice viewer / GET | 金額と請求日を表示。社内承認メモと振込先口座の変更履歴は返さない。 |
Bob editor / PATCH | 担当請求書なら明細を更新可能。ただし承認状態やtenant_idをリクエスト本文から変更させない。 |
tenant-admin / approve | 同じ企業内で承認権限と対象状態を確認。自分が作成した請求書を自己承認できるかは業務ルールで決める。 |
大量代入も認可の問題です。PATCHのJSONへ`role`、`tenant_id`、`approved=true`を混ぜて送れる場合、サーバが全フィールドを無条件に更新すると、対象IDの認可が正しくても権限外の属性変更が起こります。受け入れるフィールドを操作別に列挙し、変更前後を監査します。
6-2. 競合とキャッシュを含む再検証
アリスが画面を開いた直後に4101の所属が変わった場合、画面表示時の許可を後の更新へ流用してはいけません。更新時点でDBの最新状態を確認し、`WHERE id=4101 AND tenant_id=10 AND status='draft'`のように状態も条件に入れて更新件数を確認します。0件なら再取得して拒否理由を調べます。
CDN、ブラウザ、APIのキャッシュも考えます。企業A専用のレスポンスを共有キャッシュへ保存すると、認可済みAPIでも他社へ内容が返る可能性があります。認証付き応答のキャッシュ方針、キーに含める主体・企業、権限変更時の無効化を確認します。DBで拒否したログだけでは、キャッシュから漏れた応答は見つからない場合があります。
6-3. 修正を確認するテストの軸
自動テストでは、利用者、企業、役割、対象所有者、状態、HTTPメソッドを変えた表を用意します。正常なAlice→4101は許可し、Alice→5201、viewer→approve、Bob→担当外の更新、移管済み4101への旧企業アクセスは拒否することを確認します。全件取得やCSVも同じ表で検証します。
レスポンスコードだけでなく、DBの更新件数、返した項目、監査ログを確認します。403と404を使い分けても、レスポンス時間や件数の違いで存在が漏れる場合があります。対策後の復旧判定は、拒否すべき経路が全て閉じ、正規業務が続けられることの両方です。
7. 科目B(午後)の判断と演習
演習1:連番ID
条件:アリスが4101を5201へ変えてGETした。質問:防ぐ確認は何か。解答:対象請求書の所属企業とアリスの信頼済み所属・閲覧権限を照合する。誤答『IDをUUID化』は推測しにくくするだけで認可にならない。
演習2:RBACのみ
条件:アリスはviewerで、企業Bの5201も請求書である。質問:viewerなら閲覧可能か。解答:不可。対象のtenant_idを追加判定する。誤答『viewerはread可』は役割と対象範囲を混同する。
演習3:垂直の昇格
条件:アリスが自社の4101を承認APIへPOST。質問:何を確認するか。解答:承認操作に必要な役割と対象状態。誤答『自社データなので許可』は操作権限を無視する。
演習4:一覧API
条件:詳細APIはtenantで絞るがCSV出力は全件取得する。質問:修正は十分か。解答:不十分。CSVも同じ認可を適用する。誤答『詳細だけ守ればよい』は別経路の漏えいを見落とす。
演習5:失効直後
条件:admin権限を剥奪したのに既存セッションが旧権限を持つ。質問:何をするか。解答:認可キャッシュとセッションの更新・失効を行い、剥奪後の要求が拒否されることを試験する。誤答『DBのroleを書き換えた』は実効を確認していない。
演習6:判断不能
条件:認可サービスが応答しない。質問:既定で許可してよいか。解答:原則拒否する。誤答『可用性のため許可』は権限のない要求も通してしまう。必要な例外は別手順で限定する。
8. 一次資料
OWASP Authorization Cheat Sheet:既定拒否と要求ごとの検査
この記事についてAIに深掘り質問する
ChatGPT、Claude、Perplexityにこの記事を参照させ、要点の確認や疑問点を自由に質問できます。
次におすすめの学習
編集・検証について
編集・検証:IT資格ラボ編集部
IPAが公開する試験要綱・シラバス・過去問題と、各技術の公式資料を優先して内容を確認しています。制度変更や誤りを確認した場合は、記事を見直して更新します。
編集方針・情報源・訂正方針を見る