IDOR(安全でない直接オブジェクト参照)とは?起きるパターンと対策法

IDOR(安全でない直接オブジェクト参照)とは?起きるパターンと対策法

#セキュリティ#Web開発#脆弱性対策

IDOR(安全でない直接オブジェクト参照)は、URLやパラメータのIDを書き換えるだけで他人のデータにアクセスできてしまう脆弱性です。 対策の勘所は、リソースを取り出すときにサーバ側で必ず所有者を確認できているかどうかです。

IDORとは

IDOR(Insecure Direct Object Reference、安全でない直接オブジェクト参照):リクエストに含まれるIDから直接リソースを取り出す際に、そのリソースが本人のものか確認しないことで、他人のデータを操作できてしまう脆弱性です。 所有者チェックの漏れが根本原因になります。

/orders/1024のIDを1025に変えるだけで他人の注文が見えるような、単純だが被害の大きい欠陥です。 情報の閲覧だけでなく、更新や削除のエンドポイントで同じ漏れがあれば、他人のデータを書き換えられます。 APIの認可不備の代表格であり、OWASP API Security Top 10ではBOLA(オブジェクトレベル認可の不備)として1位に挙げられています。

IDORが起きるパターン

典型的な弱点は次のとおりです。

  • リクエストのIDだけでリソースを取得し、ログイン中のユーザーが所有者かを確認していない
  • 認証(ログインしているか)は見ているが、認可(そのデータにアクセスしてよいか)を見ていない
  • 連番のIDを使っており、値を1つずらすだけで他人のリソースを総当たりできる
  • ファイル名やユーザー名など、推測しやすい識別子で直接リソースを参照している
  • 一覧APIで自分のデータに絞り込む条件を付けず、IDの指定だけで任意の行を返す

共通するのは「リクエストのIDを信用してリソースを返し、それが本人のものかをサーバで確かめていない」という点です。

対策法

原則は「リソースは必ずログイン中のユーザーを起点に絞り込んで取り出す」ことです。

  • クエリの条件に現在のユーザー(current_user)を含め、本人のリソースだけを取得する。これが本命の対策になる
  • 認証だけで済ませず、操作対象ごとに所有者や権限を確認する認可チェックを入れる
  • IDを連番ではなく推測困難な値(UUIDなど)にし、総当たりのコストを上げる(補助策)
  • 参照だけでなく更新、削除、一覧のすべてのエンドポイントで同じ所有者チェックを徹底する

推測困難なIDは補助であり、本命はサーバ側での所有者に基づく絞り込みです。 リソースを扱う全エンドポイントを洗い出し、current_user起点の取得に統一するのが費用対効果の高い進め方になります。

Rails での事例

危険な実装は、リクエストのIDをそのままモデルの検索に渡す形です。

# 危険:ログイン済みなら誰の注文でも取得できる
def show
  @order = Order.find(params[:id])
end

Order.find はテーブル全体からの検索であり、URL の ID を書き換えれば他人の注文が返ります。 直し方は、取得の起点を current_user の関連に変えることです。

def show
  @order = current_user.orders.find(params[:id])
end

これで発行される SQL に user_id = ? の条件が加わり、他人の ID を指定しても ActiveRecord::RecordNotFound(404)になります。 所有者チェックを if @order.user_id == current_user.id のような後付けの分岐で書く方法もありますが、書き忘れがそのまま穴になるため、関連経由の取得に統一するほうが漏れにくくなります。

更新と削除でも同じ形にします。

def destroy
  current_user.orders.find(params[:id]).destroy!
end

管理者だけ全件を扱えるようにしたい場合も、Order.find へ戻すのではなく、Pundit や CanCanCan のような認可ライブラリでロールごとのスコープを定義し、取得経路を一元化します。

まとめ

IDOR対策の要点を整理します。

  • 成立条件は「リクエストのIDを信用してリソースを返し、それが本人のものかをサーバで確かめていないこと」。認証(ログイン確認)と認可(アクセス可否の確認)の混同が典型的な背景にある
  • 本命の対策は、現在のユーザーを起点にした絞り込み(current_user.orders.find のような関連経由の取得)。後付けのif分岐は書き忘れがそのまま穴になる
  • 参照だけでなく更新・削除・一覧まで、リソースを扱う全エンドポイントで同じ形に統一する
  • UUIDなど推測困難なIDは総当たりのコストを上げる補助策で、所有者チェックの代わりにはならない
  • 管理者向けの全件アクセスは、認可ライブラリでロールごとのスコープとして定義し、取得経路を一元化する

既存コードの点検は、Model.find(params[:id]) のような「テーブル全体からの直接取得」をgrepで洗い出すところから始めるのが近道です。

関連して読める記事

CSRFも「認証は通っているのに、意図しない操作が成立してしまう」という点でIDORと地続きの脆弱性です。SQLインジェクションは、同じくリクエストの値を検証しないままデータベースに渡すことで起きます。あわせて点検すると、リクエスト由来の値の扱いをまとめて見直せます。

CSRF(クロスサイトリクエストフォージェリ)とは?起きるパターンと対策法

CSRF(クロスサイトリクエストフォージェリ)の仕組みと起きるパターン、CSRFトークンとSameSite Cookieを軸にした対策を整理します。Railsで検証を外してしまう skip_before_action の罠と、React(TypeScript)からのトークン送信ヘッダの組み込み方を、危険なコードと安全な書き方の具体例で示します。

2026年7月23日

SQLインジェクションとは?起きるパターンと対策法

SQLインジェクションの仕組みと起きるパターン、そしてプレースホルダ(パラメータ化クエリ)を軸にした対策を整理します。Rails(Active Record)で穴が開く where の文字列展開と order のカラム名、その安全な書き方を具体的なコード例で示します。

2026年7月22日
この記事をシェア