安全でない直接オブジェクト参照(IDOR)とは何か、攻撃者はそれをどのように悪用するのか、そして開発者は安全なコーディングプラクティス、アクセス制御パターン、自動テストプラットフォームを使ってIDORの脆弱性をどのように防ぐことができるのかを学ぶ。
IDORとは?
安全でない直接オブジェクト参照(IDOR)は、アプリケーションが、要求者がそのオブジェクトにアクセスする権限があるかどうかを検証することなく、ユーザーID、注文番号、ファイル名などの内部オブジェクト識別子を公開するセキュリティ脆弱性です。URLやAPIコールのパラメータを変更することで、攻撃者はアクセスすべきではないデータを閲覧、修正、削除することができます。
IDORを理解する:この脆弱性が依然として重要な理由
IDORは、次のような幅広いカテゴリーに属する。 壊れたアクセス制御IDORは、OWASPが長年にわたって最も重大なウェブ・セキュリティ・リスクの1つとしてランク付けしている。IDORの危険性はその単純さにある。攻撃者は高度な悪用技術やペイロード・エンコーディング、特権の昇格を必要としない。たった1つの変更されたパラメータ(多くの場合、単なる数字)が、個人情報を暴露する可能性がある。
典型的な脆弱なパターンは次のようなものだ:
バッシュ
/api/user/profile?id=1002
アプリケーションが所有権や認可を確認しない場合、IDを以下のように変更する。 1003 は、他のユーザーのデータを明らかにする可能性がある。
最近のアプリケーション、特にAPI、マイクロサービス、モバイルクライアントを含むアプリケーションは、多くの場合、パラメータ化されたオブジェクトアクセスに大きく依存している。このアーキテクチャは、高速で柔軟である一方で、認可チェックに一貫性がなかったり欠落していたりすると、簡単にIDORを引き起こす可能性がある。

CVE-2025-13526:実世界におけるIDORの事例
IDORを悪用した最も新しい例のひとつは、次のようなものだ。 CVE-2025-13526人気のある WordPress プラグイン OneClick Chat to Order(バージョン 1.0.8 以下)に影響を与えます。
- 脆弱性はプラグインの
ワー_オーダー_サンキュー_オーバーライド関数を使用します。プラグインはオーダーIDパラメータをURLクエリー文字列から取得する。 - 攻撃者は(認証されていないものであっても)、単純に操作することができる。
オーダーIDサンキュー」ページのURLの値を変更する(例:「サンキュー」ページのURLの値を変更する)。order_id=123456へのorder_id=123455)、他の顧客の注文詳細を取得する。公開されるデータ 氏名、電子メールアドレス、電話番号、請求/発送先住所、注文項目と価格、支払い方法のメタデータ. wiz.io+2ゴウリ・インフォセック+2 - つまり、攻撃者や自動化されたスクリプトは、数分で何千もの注文を集めることができるのだ。 中+1
- この脆弱性は CVSS v3.1 の基本スコア 7.5(高)が割り当てられており、悪用の容易さ(認証不要)とデータ漏洩の深刻さを反映している。
- 開発者はバージョン 1.0.9サイト所有者は直ちにアップグレードするよう促された。サイト所有者は直ちにアップグレードするよう促された。 ゴウリ・インフォセック+1
この現実世界の侵害は、IDORが理論上のバグでもレガシーバグでもないことを示している。

IDORが発生する現実世界の一般的なシナリオ
IDORは、ユーザー制御の入力を介して内部オブジェクトを参照するあらゆるシステムに出現する可能性がある。以下は一般的なコンテキストである:
| アプリケーション・タイプ | オブジェクトの例 | IDORが起こる理由 |
|---|---|---|
| アカウントシステム | ユーザーID | ユーザー識別子の直接公開 |
| 電子商取引アプリ | オーダーID | 所有権の不適切な検証 |
| ファイル管理 | ファイルID | ファイルへのアクセス制御の欠如 |
| チケット・プラットフォーム | チケットID | ユーザーが他のユーザーのチケットにアクセスする |
| SaaSマルチテナント型アプリ | テナントID | テナント間のデータ漏洩 |
攻撃者はしばしば、予測可能なIDを列挙したり、連続したIDを試行したり、 認証されたリクエストを変更されたパラメータで再生したりする。
攻撃者はどのようにIDORを悪用するか(安全で制御された例)
以下はその例である。 安全なイラストの例 典型的な脆弱なパターンと、安全なパターンを示します。これらは有害なエクスプロイトではなく、開発者が安全でないパターンを認識するための、よくある間違いをモデル化したものである。
例1:Node.js / ExpressにおけるIDOR
ジャバスクリプト
// ❌脆弱 例:ユーザーが提供したIDを信頼する場合
app.get('/api/user/profile', (req, res) => {.
const userId = req.query.id;
db.users.findById(userId).then(user => {)
res.json(user);
});
});
// ✅ セキュアな例:認可の実施
app.get('/api/user/profile', (req, res) => {.
const authenticatedId = req.user.id;
db.users.findById(authenticatedId).then(user => {)
if (!user) return res.status(404).json({ error: "User not found" });
res.json({ id: user.id, email: user.email, role: user.role });
});
});
例2:Python / Flaskでよくあるパターン
パイソン
#❌ 安全でない:所有権の検証なし
app.get("/invoice")
def get_invoice():
invoice_id = request.args.get("id")
return get_invoice_by_id(invoice_id)
#✅ セキュア:パーミッションチェック追加
app.get("/invoice")
def get_invoice_secure():
invoice_id = request.args.get("id")
user_id = session["user_id"]
invoice = get_invoice_by_id(invoice_id)
if invoice.owner_id != user_id:
return {"error":"認証されていません"}, 403
請求書
例3:バックエンドとフロントエンドの複合防御(Java + React)
Java (Spring Boot)
ジャワ
// ❌ 認可チェックの欠落
GetMapping("/orders")
public Order getOrder(@RequestParam String orderId) { オーダーを取得します。
return orderRepository.findById(orderId);
}
// 安全な実装
GetMapping("/orders")
public ResponseEntity getOrder()
@RequestParam String orderId、
プリンシパル・プリンシパル) {.
Order order = orderRepository.findById(orderId);
if (!order.getUser().equals(principal.getName())){
return ResponseEntity.status(HttpStatus.FORBIDDEN)
.body(Collections.singletonMap("error", "Access denied"));
}
return ResponseEntity.ok(order);
}
リアクトサイドの安全なリクエスト
ジャバスクリプト
非同期関数fetchOrder(orderId) { 非同期関数fetchOrder(orderId) {
const res = await fetch(/orders?orderId=${orderId}, {)
ヘッダ:ヘッダー: { "Authorization":ベアラ${localStorage.getItem("token")}。}
});
if (!res.ok) throw new Error("Unauthorized or not found");
res.json()を返す;
}
IDOR脆弱性の検出:実践的な開発者のアプローチ
IDORを見つけるのは、それを悪用するよりも難しいことが多い。インジェクション脆弱性とは異なり、IDORは必ずしも明らかな技術的エラーを引き起こすとは限らない。
一般的な検出技術には次のようなものがある:
- 差分ファジング(複数のIDをテストする)
- リプレイテスト(キャプチャ→修正→リプレイ)
- マルチユーザーの役割切り替え
- パラメータ列挙
安全なファジング擬似コード:
パイソン
簡単な安全ファジングの例
ids=["1001", "1002", "1003"]。
for i in ids:
res = client.get(f"/api/user/profile?id={i}")
print(i, res.status_code, len(res.text))
IDORの防止:開発者が守るべきベストプラクティス
IDORの防止は難読化ではない。 認定サーバーレベルで一貫して実行された。
クライアントからのオブジェクト識別子を信用しない
すべてのパラメーターは変更可能だ。暗号化されたIDでさえ改ざん可能だ。
すべてのリクエストでサーバー側の認証を強制する
認知されたアクセス制御モデルを使用する:
- リレーショナルアクセス制御 (役割ベースのアクセス制御)
- アバック (属性ベースのアクセス制御)
- ACL (アクセス制御リスト)
- ポリシー・アズ・コード のようなシステムです。 オーパーツ
当局のリソース
- OWASP: https://owasp.org
PortSwiggerウェブ・セキュリティ・アカデミー: https://portswigger.net/web-security/access-control
列挙不可能な識別子を優先する
UUIDはIDORのリスクを軽減するが、排除するものではない。
マルチテナント環境におけるテナント境界の検証
クロステナントIDORは、最も深刻でコストのかかる形態のひとつである。
バックエンド-フロントエンド(BFF)レイヤーの使用
BFFは認可ロジックを一元化し、クライアント間の不整合を減らすことができる。
その他の高度な例
例 4: 認可が欠けている Go API
行く
// ❌ 脆弱なハンドラー
func GetDocument(w http.ResponseWriter, r *http.Request) {.
id := r.URL.Query().Get("id")
doc := db.FindDocument(id)
json.NewEncoder(w).Encode(doc)
}
// ✅ 所有権の検証あり
func GetDocumentSecure(w http.ResponseWriter, r *http.Request) { { GetDocumentSecure(w http.ResponseWriter, r *http.Request)
id := r.URL.Query().Get("id")
user := r.Context().Value("ユーザー").(文字列)
doc := db.FindDocument(id)
もしdoc.Owner != user {なら
http.Error(w, "Unauthorized", http.StatusForbidden)
戻る
}
json.NewEncoder(w).Encode(doc)
}
例5:GraphQLエンドポイントとオブジェクト認証
ジャバスクリプト
// ❌ 脆弱なリゾルバ
constリゾルバ = {
クエリー{
order: (_, { id }) => db.getOrder(id)、
}
};
// ✅ 所有権チェックを備えた安全なリゾルバ
const resolversSecure = {.
クエリー{
order: (_, { id }, context) => {.
const order = db.getOrder(id);
if (order.owner !== context.user.id) {.
throw new Error("Access denied");
}
リターンオーダー;
}
}
};
例 6: Rust でのセキュアなアクセス (Actix Web)
さび
// ❌ 脆弱
async fn get_ticket(path: web::Path) -> impl レスポンダ {.
let id = path.into_inner();
let ticket = db::find_ticket(&id);
web::Json(ticket)
}
// ✅ セキュアバージョン
非同期 fn get_ticket_secure(
path: web::Path、
ユーザーログインユーザー
) -> impl レスポンダ {.
let id = path.into_inner();
let ticket = db::find_ticket(&id);
if ticket.owner != user.id {.
return HttpResponse::Forbidden().json("Access denied");
}
HttpResponse::Ok().json(ticket)
}
IDOR検出の自動化:従来のツールが苦戦する理由
従来の脆弱性スキャナーのほとんどは、IDORを確実に検出することができない。なぜならIDORは、従来スキャナーができなかった2つのことを必要とするからだ:
- ビジネス・ロジックの認識
- コンテクスチュアル・マルチユーザー・テスト
シグネチャベースの検出やシングルユーザーリクエストのみに依存するスキャンツールは、特にAPIにおいて、通常IDORを完全に見逃す。
PenligentがIDORを自動的に識別する方法
そこで 寡黙AIを活用した侵入テストプラットフォームであるPenligentは、独自の優位性を提供します。従来のスキャナーとは異なり、Penligentは以下を実行します:
- 自動マルチユーザーシミュレーション
- オブジェクト間のパラメータ推論
- インテリジェントIDパターン認識
- 行動差分析
- 観察された反応に基づいて適応するAIファジング
Penligentの安全で匿名化された検出出力のサンプル:
ブイビーネット
IDORの可能性が検出されました:/orders?id=1002観察された動作:
- ユーザーAはオーダー#1003(ユーザーB所有)を受け取った。
このような洞察は、静的なツールや手作業によるレビューだけでは難しい。
PenligentでCI/CD全体のIDORリスクを削減
PenligentはCI/CDパイプラインに自然に統合され、継続的なカバレッジを提供します:
- APIとルートの自動検出
- リアルタイム許可行列推論
- ステージング環境と本番環境のような環境のスキャン
- 安全で再現可能なPoCシーケンスの自動生成
これで減る:
- ビジネス・ロジックの盲点
- マルチテナント
- 規制リスク(GDPR、HIPAA、SOC2)
結論IDORは単純だが破壊的-そして予防可能
IDORは依然として、アクセス・コントロールの脆弱性の中で最も一般的かつ有害な形態の一つである。IDORはビジネス・ロジックの中に隠れているため、従来のツールをすり抜けることがよくあります。一貫した権限チェックを実施し、予測不可能な識別子を使用し、テナント境界を検証し、Penligentのような自動テストプラットフォームを採用することで、組織は大規模なデータ暴露のリスクを劇的に減らすことができます。
IDORは、偶然や善意によって完全に排除することはできない-構造化されたアクセス制御、一貫した工学的原則、継続的なテストが必要である。

