【入門編】不適切な認証・認可によるIDOR(Insecure Direct Object Reference)の防止 – アプリケーションセキュリティ & 安全な開発防御ガイド

「URLの数字を変えるだけ」で大惨事?IDORの恐怖と、今日からできる「鍵の掛け方」

こんにちは。セキュリティの世界へようこそ。

今日は、開発現場でつい見落とされがちなのに、やられると致命傷になる「IDOR(アイドア:不適切な直接オブジェクト参照)」という脆弱性についてお話しします。

「認証(ログイン)」はしっかり実装したつもりでも、その後の「認可(権限チェック)」が抜けていると、まるで「玄関の鍵は閉めたけど、家の中の金庫は誰でも開けられる状態」になってしまいます。

今回は、この「IDOR」を身近な例えで紐解きながら、どうすれば防げるのか、現場の知見を交えて解説していきますね。

1. IDORって何?「泥棒」に例えて解説

想像してみてください。あなたは今、会員制のWebサービスを運営しています。ユーザーはログインすると、自分のプロフィール画面が見られますよね。

その時のURLがこんな感じだとします。
`https://example.com/api/users/12345/profile`

ここで、もしあなたが悪意のあるユーザーだとしたら、どう考えるでしょうか?
「この『12345』っていう数字、もしかして隣の人のIDに変えたら、その人のプロフィールが見えちゃうんじゃない?」

そう、これがIDORの正体です。
サーバー側が「このリクエストを送ってきた人は、本当にID 12345の持ち主かな?」を確認せずに、「言われた通りにID 12345のデータを表示しますよ!」と素直に返してしまう。 これがまさに、鍵の掛かっていない金庫を泥棒に差し出す行為なんです。

2. なぜこんなことが起きてしまうのか?

開発現場でよくあるのが、「ログインさえしていれば、その人は信用できるユーザーだ」という思い込みです。

  • 認証(Authentication): 「あなたは誰ですか?」を確認すること。(ログイン)
  • 認可(Authorization): 「あなたはそのデータに触ってもいい人ですか?」を確認すること。

IDORは、「認証はしたけれど、認可を忘れた」時に発生します。APIを実装する際、「ユーザーIDを受け取ってデータを返す」という機能を作ると、ついつい「動くこと」を優先して、権限チェックという「鍵の確認」をすっ飛ばしてしまうんですよね。

3. 実践!IDORを防ぐための「認可ロジック」

では、コードで具体的にどう防ぐべきか見ていきましょう。

悪い例(脆弱な実装)

// ユーザーが自分のプロフィールを取得するAPI
app.get(‘/api/users/:id/profile’, (req, res) => {
// 受け取ったIDを使ってDBからデータを引くだけ(超危険!)
const userData = db.findUserById(req.params.id);
res.json(userData);
});

これだと、誰でもURLのIDを書き換えるだけで他人の情報を盗み見放題です。

良い例(認可ロジックの実装)

必ず「現在ログインしているユーザー」と「要求されたデータ」を照らし合わせる必要があります。

app.get(‘/api/users/:id/profile’, (req, res) => {
// 1. セッション(またはトークン)から現在ログイン中のユーザーIDを取得
const currentUserId = req.session.userId;

// 2. URLで指定されたIDと、ログイン中のIDが一致するかチェック!
if (currentUserId !== req.params.id) {
// 権限がない場合は「403 Forbidden(閲覧禁止)」を返す
return res.status(403).send(“自分のデータ以外は見られません!”);
}

// 3. 一致した場合のみ、データを返す
const userData = db.findUserById(req.params.id);
res.json(userData);
});

シンプルですが、これが鉄則です。「リクエストされたIDをそのまま信用しない」。これがセキュリティの第一歩です。

4. プロからのアドバイス:IDを隠す工夫

認可ロジックをしっかり入れるのが大前提ですが、さらに防御を固める手法として「推測しにくいIDを使う」というやり方もあります。

連番(1, 2, 3…)のIDを使っていると、攻撃者は「次は4だ!」と簡単に予測できてしまいます。そこで、UUID(ランダムな文字列)を使うのが世界標準のトレンドです。

  • 悪い例: `user/101`
  • 良い例: `user/a1b2c3d4-e5f6-7890-abcd-1234567890ef`

URLが複雑になると、攻撃者が他人のIDを推測して片っ端から試す(総当たり攻撃)のが非常に難しくなります。これも立派な防御策の一つです。

最後に:セキュリティは「疑うこと」から始まる

セキュリティは、一度設定して終わりというものではありません。日々の開発の中で、「もし自分が意地悪なハッカーだったら、このURLの数値をいじるだろうか?」と、ちょっとだけ立ち止まって考えてみてください。

「ログインしているから大丈夫」ではなく、「ログインしていても、操作する対象が本当にその人のものか確認する」。この泥臭いチェックの積み重ねが、あなたのサービスを、そしてユーザーを守る最強の盾になります。

一歩ずつ、安全な開発を一緒に進めていきましょうね!何か不安なことや疑問があれば、いつでも相談してください。応援しています!

コメント

タイトルとURLをコピーしました