アクセス制御の不備とは|認証と認可の違い、管理者でなくても大量に漏れる仕組みと拒否テスト

オリジナルの写真調CGによる概念表紙。窓からの自然光が差す木製の小扉キャビネット(4列3段)のうち、1つの扉だけが自分の鍵で開いていて、ほかの扉はそれぞれの鍵穴で閉じたまま。左に「アクセス制御の不備 ログインできても、全部は見せない。」の文字。実際の事故・画面・環境を写したものではありません。

どうもTORAです。

ここ最近、個人情報流出のニュースが絶えないですよね。システムから個人情報が大量に流出するのは、たとえば管理者ではないユーザーに管理者権限がついてしまっている、みたいな場合なのか。この記事は、その疑問が出発点です。

何が原因かは事件ごとに様々で、それぞれの公表を読まないと分かりません。なのでこの記事では、ニュース全体の原因ではなく、OWASP Top 10の2025年版で1位になっている「アクセス制御の不備」に絞って、どういうことなのかを具体例で解説します。認証と認可の違い、管理者権限を手に入れなくても大量のデータに届いてしまう仕組み、防ぐために何を見直すか、拒否されるべき操作をどうテストするか、の順に書きます。根拠にしたのは、Webアプリのセキュリティ指針を公開している非営利団体OWASPの文書、クラウド各社やMDN(Mozillaが運営するWeb技術の解説サイト)の公式ドキュメント、企業の公式な公表文です。

Webサービスや業務システムを作る人、発注する人、運用する人、それにAIで個人開発している人を想定しています。

目次

アクセス制御の不備とは

OWASP Top 10:2025のA01 Broken Access Controlは、アクセス制御を、利用者が本来与えられた権限の外で行動できないようにする仕組みだと説明しています。これが壊れると、許されていない人へのデータの開示、データの改変や削除、権限の外にある業務機能の実行につながります。

順位の意味は先に分けておきます。OWASP Top 10は、OWASPに寄せられたアプリのテスト結果や、公開された脆弱性の情報などをもとに作る、Webアプリのリスクの分類です。A01は前の版に続いて、2025年版でも1位を維持しています。ただ、これは「個人情報漏えい事件の原因として一番多い」という意味ではありません。事件の原因を数えた順位ではないので、ニュースになった流出がどれもアクセス制御の不備だとは言えません。

ほかの項目との境目もあります。2025年版では、なりすましを許すような認証の失敗はA07 Authentication Failures、SQLインジェクションなどはA05 Injectionとして、A01とは別の項目です。A01は、ログインした人、あるいはログインしていない人が、許された範囲の外にあるデータや機能に届いてしまう問題です。

認証は「誰か」、認可は「何をしてよいか」

OWASPの認可の指針(Authorization Cheat Sheet)は、認可を「要求された操作やサービスが、その主体に許されているかを確かめること」と定義し、本人確認である認証とは別のものだとしています。ログインできた人が、システムで技術的にできる操作をすべて許されているわけではありません。逆に、ログイン画面や公開ページのように、ログインしていない人に許されている資源もあります。

なので、アクセス制御の不備は認証と認可の設計が良くないということか、と聞かれたら、主に認可の側の話です、という答えになります。ログインしているのが確かに本人でも、その本人が他人のデータを取れてしまえばA01です。

認証と認可の違いを4段で示した図。認証は誰かを確かめること、認可はこの人がこのデータにこの操作をしてよいかを確かめること。ログイン済みの本人でも他人のデータは許可の外で、アクセス制御の不備は主に認可の失敗。
OWASPの認可の指針の定義をもとに、認証と認可の違いを並べました。ログインできたことと、そのデータを扱ってよいことは別の確認です。

認可の失敗は、設計・実装・設定のどこでも起こります。誰が何をしてよいかを決めていない。決めたのにチェックを書き忘れた、ブラウザから送られてきた値をそのまま信じた。保存先を公開にしていた、フレームワークの初期値のままだった。そういう形です。

OWASPの検証基準ASVSの5.0.0は、認可の章V8の最初に、認可のルールを文書で定義することを置いています。そのうえで、機能(v5.0.0-8.2.1)、個々のデータ(8.2.2)、データの中の項目(8.2.3)の3つの単位で、明示的に許された人だけに絞ることを求めています。ASVSは要件をレベル1〜3に分けていて、機能とデータの単位(8.2.1、8.2.2)はレベル1、項目の単位(8.2.3)はレベル2の要件です。この記事では、そこに会社(テナント)、ファイルの保存先、権限を外したあと、の境界も足して見ていきます。

ログインの作り方やAPIキーの扱いは、AIコーディングで個人開発する人のパスワード管理|認証・APIキーの基礎に書きました。今回は、そちらで少しだけ触れた認可の部分を掘り下げます。

管理者にならなくても、大量に漏れる

管理者ではないユーザーに管理者権限がついてしまうことは、実際に原因の一つになります。ただ、一般ユーザーのまま大量のデータに届く経路もあります。

OWASPのAPI向けのリスク分類(API Security Top 10の2023年版)で1番目に挙がっているBOLA(Broken Object Level Authorization)の説明が、そこをはっきり書いています。BOLAでは、利用者がそのAPIを呼べること自体は設計どおりで、違反は個々のデータの単位で、IDを書き換えることで起きる、と。注文詳細のAPIは一般ユーザーにも呼ぶことが許されている。でも、どの注文を返すかの確認が抜けていれば、番号を変えるだけで他人の注文が返ってきます。管理者権限は一度も手に入れていません。IDの書き換えで他人のデータに届くこの問題は、IDOR(Insecure Direct Object Reference)とも呼ばれます。

1件ずつでも、IDの一覧が手に入れば件数は増えます。BOLAのページには、別のAPIから全店舗の名前を取り、それを順に差し込んで数千の店舗の売上データに届く、という攻撃シナリオが載っています。OWASPが説明のために置いた架空のシナリオですが、1か所の確認漏れが大量の流出になる道筋はこれで分かります。

仮想例の図。一般ユーザーが注文詳細APIを呼ぶのは許されているが、どの注文を返すかの確認が抜けると番号の変更で他人の注文が返り、IDの一覧が手に入れば管理者にならないまま大量のデータに届く。
仮想例です。APIを呼べること自体は許されていて、抜けているのは「この注文をこの人が見てよいか」の確認です。

仮想の業務サービスで見る7つの場面

ここからの例は、説明のために作った仮想のサービスです。実在のサービスや事故ではありません。

複数の会社が契約して使う、会員制の業務Webサービスを考えます。利用者は各社の一般ユーザー、閲覧専用ユーザー、各社の管理者、サービス運営側の管理者。扱うのは顧客情報、注文、請求書のPDF、CSV出力です。仕様として、注文を見られるのは作成した本人とその会社の管理者だけ、全件CSVを出せるのは会社の管理者だけで、それも自社の分だけ、と決まっているとします。例外は閲覧専用ユーザーで、自分に割り当てられた注文と請求書を見ることだけができ、更新・削除・出力はできません。

1. 注文番号を変えると、他人の注文が見える

一般ユーザーが自分の注文を開くと、GET /api/orders/1002 が呼ばれます。番号を1001に変えると、同じ会社の別の人の注文が返ってくる。典型的なBOLAです。APIが見ているのはログインしているかどうかだけで、注文1001をこの人が見てよいかは確かめていません。

直し方としては、取ってから比べるより、見てよい範囲に絞って取る形が分かりやすいです。OWASPのIDOR対策の指針も、利用者がアクセスできるデータの集合から探すよう勧めています。

# 危ない:番号だけで、全部の注文から探している
order = Order.find(order_id)

# 直した形:ログイン中の人が見てよい注文の中から探す
order = current_user.visible_orders.find(order_id)

この「ログイン中の人」は、サーバー側のセッションや検証済みのトークンから取ります。リクエストの本文やヘッダーに入っている user_id は根拠にしません。

BOLAのページは、セッションのユーザーIDとパラメータのIDを比べるだけでは一部のケースにしか対応できない、とも書いています。この仮想サービスでは会社の管理者も注文を見られますし、チームで共有する文書や代理で操作する機能があれば、所有者のIDだけでは判定できません。所有・所属・共有といった、人とデータの関係で判定します。

2. 会社IDを変えると、他社の顧客一覧が出る

顧客検索のAPIが ?company_id=12 を受け取り、その値で絞り込んでいるとします。13に変えると、別の会社の顧客一覧が返る。会社の境界を越える失敗です。どの会社のデータを見るかを、ブラウザから来た値で決めているのが原因です。

OWASPのマルチテナントの指針は、クライアントから来たテナントIDは選ぶための値として扱い、ログインしている人がそのテナントで操作してよいかを確かめるよう書いています。所属はサーバー側で確かめた本人の情報と、現在の所属から決めます。

混同しやすいのが、SQLをパラメータ化しているから大丈夫、という考えです。同じ指針は、パラメータ化はインジェクションを防ぐもので、テナントをまたぐアクセスは防がない、と書いています。正しく組み立てたSQLで、他社のIDを正しく検索してしまうわけです。

データベース側の行単位のアクセス制御(PostgreSQLのRow Level Security、RLSなど)は、補助として役に立ちます。ただPostgreSQLでは、スーパーユーザーやBYPASSRLS属性を持つロールにはRLSが効きません。指針は、アプリの通常のリクエストをそういうロールで接続しないこと、設定ファイルに書いたロールだけでなく、実際に動いている接続のロールも確かめることを求めています。仕組みや既定値は使うDBやサービスごとに違うので、公式ドキュメントで確認してください。

検索では、返る行以外にも気をつけるところがあります。他社の行は返さなくても、件数や「該当あり/なし」の違い、エラーメッセージの文面から、データの存在が分かることがあります。IDOR対策の指針は、存在そのものを知られたくないなら、見つからない場合と権限がない場合を同じ応答(たとえば404)にまとめるよう書いています。

3. ボタンは隠れているのに、全件CSVが出る

「全件CSV出力」のボタンは、会社の管理者にだけ表示されています。でも出力APIそのものは、一般ユーザーが呼んでも全件を返す。機能の単位の認可が抜けている状態で、API向けの分類ではBFLA(Broken Function Level Authorization)と呼ばれます。

BFLAのページは、/api/v1/users/export_all のようなURLを推測して呼べないか、GETをDELETEに変えるだけで削除できないか、という確認の問いを並べています。A01にも、画面側にだけアクセス制御を置いたアプリが、ブラウザを通さずAPIを直接呼ばれる例が載っています。ボタンを隠すのは使いやすさのためで、許可の判定にはなりません。

BFLAのページが挙げる対策は、すべての業務機能から呼ばれる一貫した認可の仕組みを持つこと、既定はすべて拒否にして機能ごとに明示的に許可することです。URLのパスだけで管理用かどうかを判断しないように、とも書いています。管理用の機能が /admin/ の外に普通の機能と並んでいるのはよくあることだそうです。

それと、会社の管理者のCSV出力も、自社の分だけに絞る必要があります。CSVを出してよい人かという機能の許可と、どの会社の分かというデータの範囲は、別のチェックです。

仮想例の図。全件CSVのボタンを画面で隠すのは使いやすさのためで許可の判定ではなく、APIは画面なしでも呼べるため、サーバー側で機能の許可(既定は拒否)とデータの範囲(自社の分だけ)を別々に確かめる。
仮想例です。ボタンの表示とは関係なく、機能の許可とデータの範囲をそれぞれサーバー側で確かめます。

4. プロフィール更新で、ロールが書き換わる

プロフィール更新のAPIに、名前やメールアドレスと一緒に "role": "admin" や "company_id": 13 を足して送ると、そのまま保存されてしまう。利用者が自分で権限を上げる、まさに管理者昇格の経路です。

フレームワークには、リクエストの値をオブジェクトの項目へ自動で割り当てる機能があります。OWASPのマスアサインメントの指針は、この機能で書き換えてはいけない項目まで更新される例として、isAdmin=true を足して送るケースを載せています。

直し方は、利用者が書き換えてよい項目を許可リストやDTO(入力専用の型)で決めて、それ以外は受け取らないことです。ロール、会社、所有者、金額のような項目は、専用の機能で、専用の権限を持つ人だけが変えられるようにします。ただ同じ指針は、DTOや許可リストは書ける項目を絞るもので、そのデータとその操作への認可の代わりにはならない、とも書いています。項目を絞っても、他人のプロフィールを更新できてしまえば、それは1の穴です。

読む側にも同じ種類の問題があります。画面には名前しか出していないのに、APIの応答には住所や電話番号、内部のフラグまで入っている、というものです。API向けの分類ではこれも含めてBOPLA(Broken Object Property Level Authorization)と呼び、返すデータを業務上必要な最小限にするよう求めています。ブラウザの開発者ツールで応答を見れば、余計な項目は誰にでも見えます。

5. 出力したファイルが、別の道から取れる

CSVや請求書PDFを作る処理は正しく認可していても、できたファイルの置き場所が穴になることがあります。保存先のクラウドストレージが公開設定で、URLを知っていれば誰でも取れる。Webサーバーの公開フォルダにバックアップや .git が残っている。A01は、公開領域にバックアップファイルを置かないよう求めていますし、認可の指針も、静的なファイルをアクセス制御の対象に含めるよう書いています。

署名付きURLは、性質を知っておく必要があります。Amazon S3のドキュメントは、署名付きURLを、持っている人にアクセスを与えるbearer token(持参人トークン)だとしています。SDKなどからは最長7日の期限を付けられます。Google Cloud Storageのドキュメントも、URLを知っている人は、期限が来るか署名に使った鍵が入れ替えられるまで、アカウントの有無に関係なくアクセスできる、と書いています。メールで転送されたり、ログに残ったりすれば、その先の人も使えます。

マルチテナントの指針は、ファイルを返す前、または署名付きURLを作る前に、そのファイルとその操作について認可すること、URLは必要なファイルと操作に限り、期限を操作に見合った長さにすることを挙げています。

時間差で動く処理もあります。CSV出力を受け付けて、あとからバッチでファイルを作る構成だと、受け付けた時点の判断が実行時には古くなっていることがあります。同じ指針は、遅れて実行される処理では権限を確認し直すこと、社内のサービスだからと認可を省かないこと、バックアップには古い所属のデータが残り得ることを書いています。

6. 退職した人の権限が残っている

退職した人のロールを外した。でもその人のログイン状態はまだ生きていて、期限の長いJWTも、送ってあった署名付きURLも使える。権限を外したことが、すべての経路に届いていない状態です。

A01は、ログアウト後にサーバー側でセッションを無効にすること、状態を持たないJWTは有効期限を短くし、長く使うものはOAuthの仕組みで取り消せるようにすることを挙げています。ASVS 5.0.0の8.3.2は、認可の判断に使う値の変更をすぐ反映するよう求め、トークンに頼っていてすぐ反映できない場合は、権限を失った人の操作を検知して元に戻す代わりの対策を求めています。ただし、この代わりの対策では情報の漏えいは防げない、とも書いています。8.3.2は最も厳しいレベル3の要件で、すべてのアプリの最低限ではありません。それでも、見られたデータや出力されたファイルはあとから取り消せない、という点は押さえておきたいところです。

アプリの中でロールを外しても、すでに渡した署名付きURLが止まるとは限りません。権限を外してから何分以内に、どの経路で拒否に変わるのかを、仕様として決めておく必要があります。

7. 最初から広いロールのまま

運用を始めるときに、とりあえず全員に広いロールを付けて、そのまま誰も見直していない。管理者権限がついてしまっている、のいちばん単純な形の一つです。

認可の指針は、仕事に必要な最小限の権限だけを付けること(最小権限)を求め、運用後も、権限が設計より広がっていないか(privilege creep)を定期的に点検するよう書いています。一度与えた権限を取り上げるのは、あとから足すより難しい、とも。

7つを分けると

仮想例の場面を越える境界で分けた図。水平は同じ権限の他人のデータ(場面1)、越境は別の会社のデータ(場面2)、垂直のうち場面3はロールが一般のまま機能の確認が抜けたもの、場面4と7はロールが書き換わる、または最初から広すぎるもの。
仮想例の場面を越える境界で分けたもので、水平は同じ権限を持つ別の人のデータへ、垂直は上の権限向けの機能や権限そのものへ届くことです。場面3はロールが一般のままで、ロールの問題は4の書き換えと7の最初から広すぎる付与です(5と6はこの図の外)。

管理者のロールを手に入れずに、一般ユーザーのまま大量のデータに届くのが1、2、3、5です。3は管理者向けの機能を呼んでいますが、ロールは一般のままで、機能の確認が抜けているだけです。権限そのものが上がってしまうのが4と7(4で company_id を書き換えれば他社への越境)。失ったはずの権限が残るのが6です。

冒頭の「管理者ではないユーザーに管理者権限がついてしまう」という疑問は、4と7にあたります。そこだけを点検していると、ほかの5つの経路は確かめないままになります。

実在の例:クラウドの公開設定(2023年のトヨタ自動車の公表)

アプリの認可チェック漏れではなく、保存先の設定の例として、会社が原因と対策を公表している事例を一つ挙げます。

トヨタ自動車は2023年5月12日、トヨタコネクティッド(TC)に管理を委託しているデータの一部が、クラウド環境の誤設定で公開状態になっていたと公表しました。外部から閲覧された可能性があるとされたのは、車載端末ID、車台番号、車両の位置情報、時刻です。対象は約215万人、外部からアクセスできる状態にあった期間は2013年11月6日から2023年4月17日までで、判明後に外部からのアクセスを遮断したとしています。

ここは区別して読みます。公表の表現は「漏洩の可能性」「外部より閲覧された可能性」で、外部からアクセスできる状態だった、ということです。トヨタは、これらのデータだけでは顧客を特定できないこと、公表時点で第三者による二次利用やコピーの残存は確認されていないことも書いています。215万人分が流出したと確認された話ではありません。

2023年7月の再発防止策の報告(5月12日と5月31日に公表した国内の事案が対象)では、担当者が誤認識でクラウドサーバーを公開に設定したこと、すでに公開設定だったクラウドサーバーに個人情報を格納してしまったことを原因としています。報告書は、担当者の判断だけで不適切な公開設定ができる状況だったこと、長い間周囲も気付けなかったこと、委託先での遵守状況の確認が不十分だったことを挙げています。対策には、社内ルールの条件に合わない場合はクラウドサーバーを公開設定にできないようにする技術的な措置と、診断ツールでクラウドの状態を常時監視する仕組みがあります。

トヨタの公表文が「アクセス制御の不備」やOWASPの分類を使っているわけではありません。A01には、外部から見える場所にファイルやディレクトリを置いてしまう弱点(CWE-552など)も含まれているので、この記事では保存先の境界の例として扱っています。公表された原因と対策から言えるのは、一人の判断で公開設定にできてしまう状態と、長い間誰も気付けない状態が問題とされ、それを技術的な制限と常時監視で防ごうとしている、というところまでです。

認可の代わりにならないもの

次のものは、どれも役には立ちます。ただ、この人がこのデータにこの操作をしてよいかを判定する仕組みではありません。

もの 役に立つこと 認可の代わりにならない理由
推測しにくいID(UUIDなど) 番号を順に試されにくくなる IDは別のAPIの応答や共有されたURL、ログから知られる。マルチテナントの指針も、ランダムなIDは認可の仕組みではないとしている
ボタンやメニューを隠す 画面の使いやすさ APIは画面を通さず直接呼べる
CORS ブラウザで動く他サイトのスクリプトに、どの応答を読ませるかを決める 制限を実行するのはブラウザで、ブラウザ以外からの直接の呼び出しは止まらない
WAF(AWS WAFの例) 送信元のIPアドレスやクエリ文字列の値などの条件に合う要求を止める 通常の検査条件は要求そのものの中身で、その注文がログイン中の人のものかという業務データの関係は判定の条件に入っていない
多要素認証(MFA) なりすましのログインを難しくする ログインした本人が権限の外に届く問題は防がない
回数制限・監視 大量に取られる速度を落とし、気付くきっかけになる 確認の抜けそのものは残る

CORSの行は、MDNの説明にある定義(サーバーがどのオリジンからの読み込みをブラウザに許すかを示すHTTPヘッダーの仕組みで、制限するのはブラウザ)をもとにしています。「ブラウザ以外からの呼び出しは止まらない」はMDNの文ではなく、この定義から言えることです。A01は逆に、CORSの設定の誤りを不備の一つに挙げています。

WAFの行は、AWS WAFのドキュメントをもとにしています。AWS WAFが挙げる判定の条件は、送信元のIPアドレスやクエリ文字列の値など、要求そのものの中身です。正しい形の要求で他人の注文番号を指定されても、それが他人のものかはアプリのデータを見ないと分からないので、こうした条件だけでは区別できません。AWS WAFは一つの製品の例で、WAF全般の仕様として書いているわけではありません。回数制限は、A01の言葉では、自動化された攻撃ツールによる害を小さくするためのものです。

防ぐために見直すこと

権限表を先に作る

最初にやるのは、誰が何をしてよいかを表にすることです。行に利用者の種類(未ログイン、一般ユーザー、閲覧専用、会社の管理者、運営の管理者、外部連携)を、列に資源と操作(自分のもの、同じ会社の他人のもの、他社のもの、全件について、閲覧・一覧・検索・更新・削除・一括出力・ファイル取得)を並べます。書き換えてはいけない項目(ロール、会社、所有者、金額など)も書いておきます。ASVSの8.1.1(レベル1)が機能とデータ、8.1.2(レベル2)が項目の読み書きのルールを文書にすることを求めていて、認可の指針も、利用者の種類と資源の組み合わせごとに許す操作を決めるよう書いています。

この表がないと、実装が正しいかどうかを確かめようがないんですよね。後で書く拒否テストも、この表から作ります。

まとめて返す経路から確かめる

一度にたくさん出ていくのは、1件ずつの画面より、まとめて返す経路です。一覧、検索、エクスポート、レポート、バッチ、GraphQLの操作、画面からはもう使っていないAPI。これらを洗い出して、どれも同じ認可を通っているかを確かめます。共通の仕組みで機能の許可をまとめても、この注文をこの人が見てよいかという個別の判定は、データを取得するところで必要です。

設定と運用の境界

保存先の公開設定、署名付きURLの期限、CORSの許可オリジン、データベースの接続ロールのように、コードの外にある設定もアクセス制御の一部です。認可の指針は、フレームワークの初期値に頼らず、設定が意図どおりに効くかを試すよう書いています。トヨタの対策にあった、ルールに合わない公開設定をそもそもできなくする仕組みと常時監視は、この層の対策の実例です。

運用では、ロールの付与の承認と定期的な棚卸し、異動や退職のときの剥奪と、その反映までの時間を決めます。A01は、拒否されたアクセスをログに残し、繰り返し失敗したら管理者に知らせることも挙げています。開発や運用を委託しているなら、委託先の設定も点検の対象です。

誰が見直すか

ここでは、発注・開発・運用の役割ごとに分けて書きます。

発注する側や企画する側は、権限表を要件として決めます。ここは業務を知っている人でないと決められません。受け入れのときは、正常に動くことだけでなく、拒否されるべき操作のテスト結果も確認します。

開発する側は、共通の認可の仕組み、範囲を絞ったデータ取得、項目の許可リストを実装し、拒否テストを自動テストに入れます。運用する側は、ロールの付与と剥奪、保存先の設定と監視、拒否ログの確認を受け持ちます。

AIに実装を頼むときに渡すこと

AIにAPIを作ってもらうとき、「ログイン必須で」とだけ伝えると、渡っている条件は認証だけです。認可のルールは、こちらから渡す必要があります。たとえばこんな形です。

このAPIの認可ルールは、添付の権限表のとおりです。
ログイン中のユーザーID、所属する会社、ロールは、サーバー側のセッション(または検証済みのトークン)から取ってください。
リクエストに含まれる user_id、company_id、role は、認可の根拠に使わないでください。
注文・顧客・請求書の取得、一覧、検索、更新、削除、CSV出力、ファイルURLの発行は、すべて共通の認可処理を通し、既定は拒否にしてください。
データは、ログイン中の人が扱ってよい範囲に絞った条件で取得してください。
更新APIで受け取る項目は許可リストで決め、role、company_id、所有者、金額は受け取らないでください。
署名付きURLは発行前に認可し、期限は仕様で決めた〇分にしてください。
最後に、すべてのエンドポイントについて、どの認可チェックを通るかを一覧にしてください。

〇分のところは、おすすめの値があるわけではありません。扱うファイルと、権限を外したときにどこまで待てるかに合わせて、仕様として決める値です。

AIが書いたコードとテストが両方通っていても、それで安心できないことは、パスワード管理の記事にも書きました。拒否のテストがあるかどうかは、人が権限表と突き合わせて確かめます。

拒否テストのやり方

ここからのテストは、自分が管理している環境か、許可を得た検証環境で、テスト用のデータを使って行うものです。本番や他人のサービスでは試しません。

OWASPのテストガイド(WSTG v4.2)は、持っているデータが違う利用者を少なくとも2人、多くの場合はそれ以上用意するよう勧めています。IDOR対策の指針の手順は、利用者AとBを作り、それぞれのデータを作り、Aでログインしてリクエストの中の参照をBのものに変え、IDが推測しやすいかどうかに関係なく拒否されることを確かめる、というものです。これを閲覧だけでなく、作成・更新・削除・エクスポート・管理操作のすべてで行うよう書いています。マルチテナントの指針も、他社への操作が拒否されることと、自社への操作が成功することの両方を確かめるよう求めています。

仮想サービスに当てはめると、確かめる組み合わせはこうなります。「本人」はある会社の一般ユーザーです。各行は、括弧の中のデータに対して操作したときの期待結果です。

誰が(どのデータに対して) 単体の閲覧 一覧・検索 更新・削除 保護項目の更新 全件CSV出力 ファイル取得 別経路
未ログイン(本人の会社のデータに対して) 拒否 拒否 拒否 拒否 拒否 拒否 拒否
本人(自分のデータに対して。許可の確認) 許可 自分の分だけ 仕様どおり許可 拒否か無視 拒否(会社の管理者だけ) 自分の分だけ 通常の経路と同じ結果
同じ会社の別の一般ユーザー(本人のデータに対して) 拒否 本人の注文が混ざらない 拒否 拒否 拒否 拒否 通常の経路と同じ結果
別の会社のユーザー(本人の会社のデータに対して) 拒否 0件 拒否 拒否 拒否 拒否 通常の経路と同じ結果
閲覧専用ユーザー(自分に割り当てられたデータに対して) 許可 割り当て分だけ 拒否 拒否 拒否 割り当て分だけ 通常の経路と同じ結果
権限を外した直後の人(外す前に扱えたデータに対して) 拒否 拒否 拒否 拒否 拒否 発行済みURLの期限が仕様どおり短い 拒否
会社の管理者(自社のデータに対して。許可の確認) 許可 自社の分だけ 許可 仕様どおり 自社の分だけ 自社の分だけ 通常の経路と同じ結果
会社の管理者(他社のデータに対して) 拒否 0件 拒否 拒否 他社の分は出ない 拒否 通常の経路と同じ結果

別経路は、HTTPメソッドを変える、画面を通さずAPIを直接呼ぶ、GraphQLの操作、古い版のAPIといった、通常の画面とは違う呼び方のことです。どこから呼んでも、通常の経路と同じ結果になる必要があります。運営側の管理者が会社をまたいで操作する機能があるなら、それは別の経路として明示的に許可し、記録を残し、その経路が想定より広い範囲に届かないことを確かめます。

拒否テストの流れを4段で示した図。許可された環境でテスト用データを使い、利用者AでBのデータへの参照に変えて全操作を試し、ステータスコードだけでなく本文・ファイル・件数にデータがないこと、読み直して状態が変わらず拒否がログに残ることを確かめる。
OWASPのIDOR対策の指針の手順をもとにした流れです。ステータスコードだけで合格にせず、応答の本文やファイルにデータがないこと、状態が変わったり出力ジョブが作られたりしていないことを見て、自分や自社の分が許可されることも確かめます。

拒否の確かめ方にも注意があります。401や403、404が返ったことだけで合格にしません。応答の本文、ダウンロードしたファイル、エラーメッセージに対象のデータが入っていないことまで見ます。一覧や検索は、エラーにならないことではなく、他人や他社の行が1件も入っていないこと、件数から存在が分からないことを確かめます。

更新や削除、保護項目の更新は、拒否の応答のあとに正規の利用者で読み直して、状態が変わっていないことを確かめます。応答は拒否なのに裏で更新が済んでいた、出力のジョブが作られていた、というのでは意味がありません。存在を知られたくない資源では、権限がない場合と存在しない場合で応答をそろえます(たとえばどちらも404)。拒否がログに残ること、権限を外した人が決めた反映時間の中で拒否に変わることも見ます。RLSを使っているなら、本番と同じロールと接続経路でテストします。マルチテナントの指針が書くとおり、違うロールで試すと、正しい設定が壊れて見えたり、すり抜けを見逃したりするからです。

この表は、自動テストにも向いています。OWASPの認可テスト自動化の指針は、権限のマトリクスをファイルにして、それを入力にした結合テストを作る形を紹介しています。BOLAのページは、認可のテストを書き、それが失敗する変更はデプロイしないよう書いています。一方で認可の指針は、こうした自動テストは専門の診断や侵入テストの代わりにはならない、としています。

一度に全部を見直すのが大変なら、一覧・検索・エクスポートのようにまとめて返す経路と、ファイルの置き場所の拒否テストから書き始めると、1つの抜けで出ていく量が大きいところを先に確かめられます。

よかったらシェアしてね!
  • URLをコピーしました!

この記事を書いた人

40代、IT業界20年弱。システム開発の仕事をしています。AIや開発、仕事やキャリアの話を中心に、ギター、音楽、革靴、デニム、腕時計など趣味のことも書きます。

目次