1. ID 改ざん攻撃 #id-tampering
最も基本的な IDOR の手法。攻撃者は次のような場所を試します:
- URL パスの数値:
/orders/12345→/orders/12346 - クエリパラメータ:
?user_id=789→?user_id=790 - POST ボディの ID:
{"order_id": 12345, ...} - Cookie 内の識別子:
account_id=42を別の値に書き換え - JWT のペイロード内の ID(署名検証が緩い場合)
自動化ツール(Burp Suite Intruder、ffuf 等)で連番を一斉に試行することで、大量のデータを抽出できる。
2. URL パス改変 #path-traversal-acl
一般ユーザの画面には表示されない管理機能の URL を、推測やログ漏洩から発見して直接アクセスする攻撃。
/admin、/admin/users、/admin/ordersなど典型的なパス- JavaScript ファイル内のルーティング情報から推測
- 古いバージョンの URL がソース管理に残っている(
/admin_v1等) - 404 と 403 の使い分けで存在を判別
管理機能には認証 + 認可の両方を必須にし、「URL を知っているだけ」では何もできない設計が必要。
3. パラメータ汚染 #parameter-pollution
POST リクエストや JSON ボディに、本来送るべきでないパラメータを追加してアプリが受け入れるかを試す攻撃。
// 通常のプロフィール更新リクエスト
POST /api/profile
{ "display_name": "美穂", "bio": "..." }
// 改ざん版 — role や is_admin を注入
POST /api/profile
{ "display_name": "美穂", "bio": "...", "role": "admin", "is_admin": true }
フレームワークによっては、リクエストの全フィールドを自動的にモデルに代入する「Mass Assignment」機能があり、開発者が意図しないフィールドが更新されてしまう。
4. Mass Assignment #mass-assignment
Rails や Django などのフレームワークには、リクエストパラメータからモデルのフィールドを一括設定する機能があります。便利だが、危険なフィールド(is_admin、balance 等)も対象になりうる。
// Rails — 危険な実装 @user.update(params[:user]) // params 全部が代入される
// Rails — Strong Parameters でホワイトリスト @user.update(params.require(:user).permit(:display_name, :bio))
各フレームワークには対策機能があるので、デフォルトで安全な書き方を覚える必要があります:
- Rails — Strong Parameters(
permit) - Django REST Framework — シリアライザの
Meta.fieldsでホワイトリスト - Spring — DTO でフィールドを限定
- Laravel — モデルの
$fillableプロパティ
5. ミドルウェアによる防御 #middleware-defense
各エンドポイントで個別に if (!user->canAccess(resource)) と書く実装は、漏れが必ず発生します。代わりに、認可チェックをミドルウェアやデコレータで強制する設計が推奨されます。
// Django REST Framework — ViewSet レベルで権限クラスを指定
class OrderViewSet(ModelViewSet):
queryset = Order.objects.all()
permission_classes = [IsAuthenticated, IsOrderOwner]
class IsOrderOwner(BasePermission):
def has_object_permission(self, request, view, obj):
return obj.user == request.user
リソース取得時に必ず権限チェックが走り、所有者でなければ自動的に 403 が返る。チェック忘れを防げる。
6. デフォルト拒否原則 #deny-by-default
Access Control の設計で最も重要な原則:明示的に許可されていない操作は全て拒否する。
悪い設計:
- 新規エンドポイントを追加するとき、デフォルトで誰でもアクセス可能。後から制限を追加。→ 制限を追加し忘れたエンドポイントが放置される
- 新しい役割が追加されたとき、何ができるかをホワイトリストで定義していないので、なんとなく多くの操作ができてしまう
良い設計:
- デフォルトの認可ポリシーは「拒否」。各エンドポイント・各リソースで明示的に「この役割の人のみ許可」と書く
- 新規機能のリリース前に、認可ルールが明示的に書かれているかをレビューチェックリストに含める
Access Control の脆弱性は、テストで検出するのが難しい(正常系のテストは通るが、認可チェックが書かれていないことに気づけない)。設計時のレビューと、コードレビュー時の認可チェック必須化が、最も効率的な防御です。