【入門編】 Broken Access Control (不適切なアクセス制御) の列挙とIDOR – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

こんにちは!Webアプリケーションを作ったり、会社のITまわりを担当したりする中で、「セキュリティってなんだか難しそうだな…」と感じていませんか?

今回は、Webシステムのセキュリティ診断(ペネトレーションテスト)の現場でも本当によく見つかる、そして初心者の方でも一番直感的に理解しやすい「IDOR(Insecure Direct Object Reference:安全ではない直接オブジェクト参照)」という脆弱性についてお話していきます。

小難しい専門用語はなるべく使わず、私たちの身近にある「家の鍵」や「郵便受け」に例えて優しく解説していきますので、一歩ずつ一緒に学んでいきましょう!

—

1. 「IDORってなぁに?」身近な例えで理解するアクセス制御

まずは、IDORがどういう仕組みで起きるのかをイメージするために、こんなシチュエーションを想像してみてください。

あなたはとあるマンションに住んでいます。あなたの部屋番号は「101号室」です。
郵便受けの鍵がしっかりかかっていれば、他の人から手紙を盗まれる心配はありませんよね。でも、もしその郵便受けが…

  • 「ダイヤル錠がついているけれど、数字を 101 から 102 に変えるだけで、隣の人の郵便受けがパカッと開いてしまう」
  • 「そもそも鍵がついておらず、誰でも自由に他人の郵便受けのフタを開けられる」

そんな状態だったらどうでしょう?これって、すごく危ないですよね。

Webの世界でもこれと全く同じことが起きています。これがBroken Access Control(不適切なアクセス制御)であり、その代表格がIDORです。

ログインしているから大丈夫、ではない?

よくある誤解が、「うちのシステムはパスワードを入れてログインしないと使えないから安全だよね」というものです。

先ほどのマンションの例で言えば、「マンションのオートロック(ログイン)を突破して中に入った住人が、他の人の部屋のドアノブをガチャガチャ回したら、鍵がかかっておらず勝手に入れてしまう状態」がまさにIDORです。

ログインしているユーザーであっても、「自分以外の人のデータを見ていい権限があるかどうか」をシステムがきちんとチェックしていないと、この問題が発生してしまいます。

—

2. 攻撃者はどうやってIDORを見つけるのか?(メカニズムの解説)

ペネトレーションテスト(攻撃者の視点で行う安全性のテスト)の現場では、私たちはどのようにこの弱点を見つけているのでしょうか。その手口を少しだけ覗いてみましょう。

例えば、あなたが自分のプロフィール画面を開いたとき、ブラウザのアドレスバー(URL)が次のような形になっているとします。

https://example.com/user/profile?id=1001

この id=1001 という部分は、データベース上で「あなたを識別するための番号(オブジェクト参照)」です。ここで、セキュリティのテストをする私たちは、次のような意地悪な(でも攻撃者は必ず試す)ことを考えます。

  • 「自分のIDが 1001 なら、この数字を 1000 に書き換えたらどうなるだろう?」
  • 「もしかして、他のユーザーの個人情報やクレジットカード情報が見えてしまうのでは?」

もしここで、URLの数字を 1000 に書き換えただけで、全く知らない他人の名前やメールアドレスが表示されてしまったら…これがIDORの成立です。システムが「今このリクエストを送っている人が、本当にそのデータを見てもいい人柄かどうか」を確認していないために起きてしまいます。

—

3. 脆弱なコードと安全なコードの比較

それでは、開発の現場でどうしてこれが起きてしまうのか、具体的なプログラム(PHPを例にします)を見てみましょう。

【危険な例】IDORがあるプログラム

以下のコードは、URLから受け取った id をそのままデータベースに問い合わせて、データを画面に出してしまっている例です。

<?php
// 危険なコード例:ログインしているかの確認はあるが、権限のチェックがない!
session_start();
$my_user_id = $_SESSION['user_id']; // 現在ログインしている自分のID

// URLパラメータからユーザーIDを取得(例: ?id=1002)
$target_id = $_GET['id'];

// データベースから対象のデータを取得
// ★問題点:他人のIDを指定されても、そのままデータを取ってきちゃいます!
$sql = "SELECT * FROM users WHERE id = " . $target_id;
$result = db_query($sql);
$user_data = db_fetch($result);

// 画面にデータを表示
echo "名前: " . $user_data['name'];
echo "メール: " . $user_data['email'];
?>

このコードでは、たとえあなたがログインしていても、URLの ?id= の部分を書き換えるだけで、データベースにある他のユーザーの情報を自由に見放題になってしまいます。

—

【安全な例】しっかりアクセス制御(認可)を入れたプログラム

では、これをどう直せばよいのでしょうか?答えは簡単です。「今リクエストしている人と、取得しようとしているデータが本当に一致しているか(あるいは管理者権限があるか)」をプログラムでしっかり比較するのです。

<?php
// 安全なコード例:認可ロジックをしっかりと実装する
session_start();
$my_user_id = $_SESSION['user_id']; // 現在ログインしている自分のID

$target_id = $_GET['id'];

// ★対策:URLで指定されたIDと、今ログインしている人のIDが一致するかチェック!
if ($target_id != $my_user_id) {
    // 一致しない場合はエラーにする(または403 Forbiddenを返す)
    header("HTTP/1.1 403 Forbidden");
    echo "アクセス権限がありません。";
    exit;
}

// 一致した場合のみ、安全にデータを取得して表示する
$sql = "SELECT * FROM users WHERE id = ?";
$stmt = db_prepare($sql);
$stmt->execute([$target_id]);
$user_data = $stmt->fetch();

echo "名前: " . $user_data['name'];
echo "メール: " . $user_data['email'];
?>

このように、「自分のデータ以外は触らせない」という防衛線をプログラムの中に必ず引くことが、Broken Access Controlを防ぐ一番の近道になります。

—

4. 防御側としての意識とHTTPヘッダーの役割

ペネトレーションテストやインフラ構築の現場では、プログラムの修正だけでなく、通信の仕組みやヘッダーの役割を正しく理解することも大切です。

よくある勘違いとして、「隠しページにしておけば誰もURLに気づかない(Security through obscurity)」という考え方があります。例えば、URLに推測しにくい長くてランダムな文字列(UUIDなど)を使ったとしても、それ自体は完全な解決策(認可の代わり)にはなりません。

なぜなら、ブラウザの履歴や、JavaScriptのコード、外部へのリンク(リファラー)などを通じて、その「隠されたURL」が意図せず外部に漏れてしまうことが多々あるからです。URLが推測しにくいことと、アクセス権限があることは、全く別の問題として捉えなければなりません。

また、Webアプリケーションを保護する際には、ブラウザに対して「予期せぬ動作や不正な読み込みを防いでね」と伝える各種セキュリティヘッダー(例:Content-Security-Policy や X-Content-Type-Options など)の設定も重要ですが、IDORのような「ロジックの隙」は、残念ながらサーバーの設定やWAF(Webアプリケーションファイアウォール)だけで完全に防ぐのは難しいのが現実です。だからこそ、アプリを作る段階での「正しいアクセス制御」が命綱になるのです。

—

まとめ:一歩ずつ安全なシステムを作っていきましょう!

今回は、不適切なアクセス制御とIDORの仕組みについて、身近な例えを交えながら解説しました。

  • IDORとは?:URLの数字などを書き換えるだけで、他人のデータが見えてしまう恐ろしい脆弱性。
  • なぜ起きる?:「ログインしているか(認証)」だけでなく、「そのデータを触る権利があるか(認可)」をプログラムが確認していないから。
  • どう防ぐ?:サーバー側で、リクエストされたデータが本当にそのユーザーのものであるかを必ずチェックするコードを書くこと。

セキュリティの対策と聞くと身構えてしまうかもしれませんが、基本の考え方は「うちのシステムは、誰が何を触っていいんだっけ?」というルールを一つひとつ丁寧にプログラムで整理していく作業です。

焦らず、一歩ずつ、安全で信頼されるシステム作りを一緒に楽しんでいきましょう!

コメント

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