セキュリティ記事ホーム
·7 IDOR認可実例

認可の脆弱性、実例 — URLの数字一つが全顧客データを開いてしまう

IDORは自動スキャナーが最も捕まえにくい代表的な脆弱性です。実際のパターンとコードレベルでの防ぎ方。


URLの/orders/1042/orders/1043に変えただけなのに他人の注文履歴が見えてしまうなら、それは偶然ではなく認可(Authorization)の脆弱性です。業界ではIDOR(Insecure Direct Object Reference)と呼ばれ、自動スキャナーが最も捕まえにくい脆弱性の一つです。

認証と認可は違う

ログインできるかどうか(認証、Authentication)と、ログインした人がそのデータを見る資格があるか(認可、Authorization)はまったく別の問題です。多くのサービスはログインは丁寧に作りますが、「このユーザーがこのリソースの所有者か」は見落としがちです。

実際にはこう突破される

GET /api/orders/1042    → 自分の注文(正常)
GET /api/orders/1043    → 他人の注文がそのまま見える(脆弱)

サーバーコードがおおよそこうなっているときに発生します。

// 脆弱なコード: idだけで検索し、所有者確認がない
app.get('/api/orders/:id', async (req, res) => {
  const order = await db.order.findUnique({ where: { id: req.params.id } });
  res.json(order);
});

ログインしているかどうかだけを確認し、「この注文がログインユーザーのものか」は確認していません。数字のIDを順番に変えていくだけで、全顧客の注文を一通り見ることができます。

なぜスキャナーが見落としやすいのか

一般的な自動スキャナーは「このAPIが200を返すか」「SQLインジェクションが可能か」といったパターンはよく捕まえます。しかしIDORは正常に200と正しいデータを返すため、そのデータが「誰のものか」というビジネス上の文脈を理解しなければ問題に気づけません。これは単純なパターンマッチングより一段深い分析が必要です。

直し方

// 修正: 検索条件に必ず所有者(userId)を含める
app.get('/api/orders/:id', async (req, res) => {
  const order = await db.order.findFirst({
    where: { id: req.params.id, userId: req.user.id },
  });
  if (!order) return res.status(404).end();
  res.json(order);
});

原則は一つです。「検索条件には常に現在ログインしているユーザーを含める」。 IDだけで検索しているクエリがあれば、すべて疑ってください。

テストの仕方

最も確実な方法は、アカウントを2つ作り、Aアカウントでログインしたまま、Bアカウントのリソースidを直接リクエストしてみることです。200と正常なデータが返ってきたら問題があります。404か403が返るのが正常です。


IDORには派手なハッキング技術は必要ありません。ブラウザのアドレスバーで数字を一つ変えるだけで発見され、悪用されます。だからこそ、より危険なのです。

WhiteHat Codeのディープスキャンは、コードのビジネス上の文脈も合わせて分析し、こうした認可漏れのパターンを見つけ出します。無料スキャンで今すぐ確認してみてください。

AIによる攻撃には、AIで備える。

スキャン

セキュリティ記事