IDOR(Insecure Direct Object Reference、安全でない直接オブジェクト参照)は、URLやパラメータに含まれるIDを変えるだけで、本来は見られない他人のデータを閲覧・変更できてしまう脆弱性です。原因は、そのデータへの権限をサーバーが確かめていないことです。対策の中心は、データにアクセスするたびに「この利用者に許可されているか」をサーバー側で確かめることです。
IDORとは
OWASPのチートシートは、IDORを次の3つがそろったときに成り立つものとして説明しています。
IDORが成り立つ3つの条件
| 条件 | 例 |
|---|---|
| 保護すべきオブジェクトがある | アカウント、文書、注文 |
| オブジェクトを指す参照を利用者が操作できる | URLのID、フォームの隠し項目、ファイル名 |
| オブジェクト単位の認可チェックがない | ログインの確認だけで処理している |
OWASPが挙げる例は、/users/123 のプロフィールページです。この数字を変えたときに他人のプロフィールが表示されるなら、IDORがあります。参照は数字に限りません。ファイル名やUUIDでも、権限を確かめていなければ同じ問題になります。
IPAの「安全なウェブサイトの作り方」も「アクセス制御や認可制御の欠落」を取り上げ、注文番号を指定して他の利用者の注文情報を閲覧できてしまう例を示しています。
OWASP Top 10での位置づけ
IDORは、OWASP Top 10:2025で1位の「A01 Broken Access Control(アクセス制御の不備)」に、よくある例の一つとして挙げられています。全項目の概要はOWASP Top 10の解説にまとめています。
この100%はA01全体の数字で、IDORだけの割合ではありません。
認証と認可の違い
IDORを理解するには、認証と認可を分けて考える必要があります。
認証
- 相手が誰かを確かめる
- パスワードやパスキーで確認する
- ログイン画面で行うことが多い
認可
- その相手に許可された操作かを確かめる
- データや操作ごとに判定する
- リクエストのたびに行う
ログインを必須にしていても、認可がなければIDORは防げません。ログインできる利用者なら誰でも、他人のIDを指定できてしまうからです。
IDORが起きるときの処理の流れ
- ログイン済みの利用者からリクエストが届く認証は通っている
- サーバーが指定されたIDでデータを探す持ち主を条件に入れていない
- 持ち主を確かめずに応答する他人のデータも返してしまう
対策1:データの範囲を利用者に絞って検索する
OWASPが優先して勧めているのは、現在の利用者が持つデータの範囲で検索する方法です。IDだけで探してから確かめるのではなく、検索の条件に持ち主を入れます。
次の例では、利用者が指定した請求書のIDと、ログイン情報から得た利用者のIDの両方を条件にしています。
const findInvoice = async ({ invoiceId, session }) => {
const { rows } = await database.query(
"SELECT id, amount FROM invoices WHERE id = $1 AND owner_id = $2",
[invoiceId, session.userId],
);
return { invoice: rows[0] ?? null };
};
ポイントは、owner_id に渡す値をリクエストの中身ではなくセッションから取ることです。IPAも、利用者IDを外部のパラメータからではなくセッション変数から取得する方法を根本的な解決策として示しています。
取得後に持ち主を比べる方法もあります。ただしOWASPは、この方法では「存在しない」と「権限がない」を区別できてしまうと説明しています。データの存在自体を知られたくない場合は、範囲を絞った検索を使い、どちらの場合も同じ404の応答を返します。
対策2:認可チェックをアプリ全体の仕組みにする
機能ごとに手で書くと、1か所の漏れがそのまま脆弱性になります。OWASPの認可チートシートとTop 10は、次の点を挙げています。
認可の設計で押さえる点
| 項目 | 内容 |
|---|---|
| 既定は拒否 | 公開するものを除き、どのルールにも当たらなければ拒否する |
| 全リクエストで確かめる | AJAXやサーバー間の呼び出しも含め、送信元を問わず確かめる |
| 仕組みを1つにする | 一度作った仕組みをアプリ全体で再利用する |
| サーバー側で判定する | 画面の制御は使いやすさのためのもので、許可の根拠にしない |
| 持ち主に基づいて判定する | 誰でもどのレコードでも操作できる状態にしない |
| 失敗を記録する | 認可の失敗をログに残し、繰り返されるなら管理者へ通知する |
読み取りだけを守って、更新や削除を忘れないようにします。OWASP Top 10は、POST・PUT・DELETEのアクセス制御が欠けているAPIも典型例に挙げています。
対策3:IDを推測しにくくする
連番のIDは、別のIDを試しやすくします。OWASPは多層防御の一つとして、ランダムな文字列やUUIDなど、長いランダムな値を使う方法を挙げています。数値IDの暗号化は安全に行うのが難しいため、避けるよう説明しています。
テストで確かめる
認可の漏れは、持ち主の違う利用者を用意すれば確かめられます。自分たちが管理するテスト環境で、次の手順を自動テストに組み込みます。
権限の違う利用者を2人用意する
利用者Aと利用者Bを作り、それぞれが持つデータ(文書や請求書など)を用意します。
Aとしてログインし、Bのデータを指定する
Bのデータの参照を指定したリクエストを、Aのセッションで送ります。
拒否されることを確かめる
IDが推測しやすいかどうかに関係なく、拒否されることを確認します。読み取りに加えて、作成・更新・削除・エクスポート・管理操作も同じように確かめます。
OWASPは、自動テストは手動の診断の代わりにはならないものの、基本的な問題を早く安く見つける手段になるとしています。
よくある質問
IDORとSQLインジェクションは何が違いますか?
SQLインジェクションは、入力値がSQLの命令として解釈されることで起こります。IDORでは、SQLは正しく動いたまま、権限のないデータが返ります。プレースホルダを使っていてもIDORは防げないため、別に対策が必要です。SQLインジェクションはこちらの解説にまとめています。
UUIDを使っていれば安全ですか?
安全とは言えません。推測はしにくくなりますが、OWASPはあくまで補助の対策としています。データごとの認可チェックは、UUIDを使っていても必要です。
権限がないときは403と404のどちらを返すべきですか?
データの存在自体を知られたくないなら、存在しない場合と同じ404を返します。OWASPは、アカウントの有無を知る権限のない相手に、その有無を明かすべきではないと例を挙げて説明しています。
出典: OWASP Insecure Direct Object Reference Prevention Cheat Sheet、OWASP Authorization Cheat Sheet、OWASP Top 10:2025 A01 Broken Access Control、IPA「安全なウェブサイトの作り方」アクセス制御や認可制御の欠落



