はじめに ── 認証は通ったのに、他人のデータが見えてしまった
以前の私は、ログイン機能を作れることに安心していました。パスワードをハッシュ化して保存し、ログインしていないユーザーははじく。認証まわりはそれなりに気にしていたつもりでした。
そんな私が書いていた API は、たとえばこんなコードでした(当時は FuelPHP を使っていました)。
// GET /api/users/{id} (FuelPHP)
$user = Model_User::find($id);
return $this->response($user);
ログインは必須にしてあります。だから安全だと思っていました。ところがある日、/api/users/123 の 123 を 124 に書き換えてリクエストを送ってみたら、他人のユーザー情報がそのまま返ってきたのです。ログインしたまま、URL の数字を1つ変えただけで。
これが IDOR(Insecure Direct Object Reference) と呼ばれる典型的な脆弱性です。原因は「認証はしていたが、オブジェクト単位の認可をしていなかった」こと。認証(あなたが誰か)と認可(その操作をしてよいか)は別物で、私はこの2つを混同していました。
この記事は、そんなちょっと前の私に向けて書きます。
なお本記事は、社内で開催しているセキュリティ勉強会(全6回)の第1回「認証・認可」をベースにしています。第2回以降では、インジェクションや SSRF、XSS、暗号、ネットワーク、ログといったテーマを回を分けて扱っていく予定です。当日の発表スライドも公開しているので、あわせてご覧ください。
想定読者:
- ログイン機能は作れて認証は気にしているが、認可はあまり意識していない Web アプリ開発者
-
find($id)で取得したものを、所有チェックなしにそのまま返していた人 - 「認証と認可って何が違うの?」がふわっとしている人
この記事のゴールは、認証を通しても他人のデータが見えてしまう理由を理解し、認可を1箇所に明示的に集約して防ぐ設計の第一歩を踏み出すことです。IDOR を実演で体感し、フレームワーク(Laravel / FuelPHP)での守り方までを順に見ていきます。
先に結論(この記事で伝えたい3点)
細かい説明に入る前に、いちばん伝えたいことを3つ先に出します。
- 認証(ログイン)が確認するのは「あなたが誰か」までです。「その操作をしてよいか」は別問題で、ここを分けて考えるのが第一歩です(認証 ≠ 認可)。
-
find($id)で取得できたことは「見てよい」ことを意味しません。取得できる ≠ アクセスしてよい。ID を書き換えるだけで他人のデータに届いてしまうのが IDOR です。 - 「これはこのユーザーのものか」という認可は、各所に散らさず1箇所に明示的に集約します。Laravel なら Policy、仕組みの薄い FW なら自前の集約層に寄せます。
この3点を、以降の本文でほどいていきます。
この記事で扱うこと・扱わないこと
対象環境とバージョンは次のとおりです。
- Laravel 13.x(2026年時点の現行安定版)の Gate / Policy による認可
- FuelPHP 1.x(レガシー。公式ドキュメントの著作権表記は 2010-2019)の Auth パッケージ
- OWASP: API Security Top 10 の API1:2023、Web の A01:2021
- 言語は PHP
この記事はオブジェクト単位の認可(と、その欠落である IDOR)に集中します。認証やセキュリティの周辺トピックは深掘りしません。範囲を絞るために、次の項目は本記事では扱わないことを先に断っておきます。
- パスワードの安全な保存や、ハッシュ・暗号の仕組みは扱いません(第4回で扱います)。
- ログイン後のセッション管理、XSS / CSRF は扱いません(第3回で扱います)。
- 総当たりの試行ログ監視やインシデント追跡は扱いません(第6回で扱います)。
- 多要素認証(MFA)や認証強度(NIST の AAL)といった認証自体の深掘りは扱いません(認証自体の復習は、記事末の「あわせて読みたい」で紹介する認証の復習記事に譲ります)。
これらはいずれも重要ですが、1記事に詰め込むと焦点がぼやけます。ここでは「認証を通した後」に絞ります。
識別・認証・認可は別物 ── アクセス制御の土台
まず言葉を整理します。よく混同されますが、識別・認証・認可は別の段階です。
- 識別(Identification): 「私は誰々です」と名乗る段階(ユーザー ID の提示など)。
- 認証(Authentication): その名乗りが本物かを確認する段階(パスワード照合など)。
- 認可(Authorization): 本人確認が済んだ後に、何を許可するかを制御する段階。
CCT の教材では、この流れを次の4ステップで説明しています。資格情報の提示 → データベースとの照合による検証 → アクセス権の付与 → 許可された操作のみの実行、という順序です。認可は「本人確認に成功した後に、読み取りは可・書き込みや削除は不可」のように、できることを絞る役割を担います(出典: CCT eBook 書籍473/PDF484、書籍513/PDF524)。
そもそもアクセス制御とは何でしょうか。CCT では「資産やリソースへのアクセスを選択的に制限する方法」と定義し、その目的を機密性・完全性・可用性の維持としています(出典: CCT eBook 書籍473/PDF484)。認可はこのアクセス制御を実現する中核です。
登場人物: Subject / Object / Reference Monitor / Operation
アクセス制御を考えるとき、次の4つの登場人物で整理すると見通しが良くなります(出典: CCT eBook 書籍475/PDF486)。
- Subject(主体): 操作をしようとする人やプロセス(ログイン中のユーザーなど)。
- Object(客体): アクセスされる対象(ユーザー情報や投稿などのリソース)。
- Operation(操作): 読み取り・書き込み・削除などの行為。
- Reference Monitor(参照モニター): Subject が Object に対して Operation してよいかを判定する門番。
この「門番(Reference Monitor)」がこの記事の主役です。図にすると、すべてのアクセスは門番を通るのが理想です。
後で見る IDOR は、まさにこの門番が仕事をしていない状態です。この図は覚えておいてください。
最小特権とデフォルト拒否
認可を設計するときの原則で、いちばん実装に効くのが**最小特権(Principle of Least Privilege)**です。これは、必要最小限の権限だけを与えるという考え方です。ほかにも職務の分離(Separation of Duties)や知る必要性(Need-to-know)といった原則があります(出典: CCT eBook 書籍476-478/PDF487-489)。
実装の観点で大事なのは、デフォルトは拒否という考え方です。「明示的に許可したものだけ通す」設計にしておけば、うっかり許可漏れがあっても安全側に倒れます。IDOR は逆に「明示的に拒否していないものが通ってしまう」状態だと言えます。
認証は「誰か」までしか守らない
ここが今回いちばん強調したい点です。認証が確認するのは「あなたが誰か」までです。
認証の要素には、次のようなものがあります(出典: CCT eBook 書籍494-495/PDF505-506)。
- Something you know: 知っていること(パスワードなど)
- Something you have: 持っているもの(スマホ・トークンなど)
- Something you are: 本人の特徴(指紋・顔など)
これらを組み合わせて本人確認の強度を上げるのが認証の世界です。ただし、どれだけ認証を固めても、認証が答えるのは「この人は確かに山田さんだ」までです。「山田さんが佐藤さんのデータを見てよいか」には、認証はいっさい答えません。
そこに答えるのが認可です。CCT でも、認可は「本人確認に成功した後に何を許可するかを制御する」ものとされています(出典: CCT eBook 書籍513/PDF524)。つまり認証を通した"後"こそが認可の主戦場であり、私が穴を空けていたのもここでした。
なお、認証自体の深掘り(中間者攻撃である AiTM、MFA 疲労攻撃、NIST SP 800-63 の認証強度 AAL など)は本記事では扱いません。ここでは「認証は本人確認まで」という前提だけ押さえて、認可の話に進みます。
【実演】ID を書き換えたら他人のデータが見えた ── IDOR
言葉だけだとピンと来ないので、実演します。以下は説明用のフィクスチャで、example.com を使った架空のデータです(実在の個人ではありません)。
まず、ログイン中の私(id が 123)が自分の情報を取得します。
GET /api/users/123
{"id":123,"name":"山田太郎","email":"taro@example.com"}
自分の情報が返ってきました。ここまでは正常です。次に、URL の 123 を 124 に書き換えるだけで、同じログイン状態のままリクエストしてみます。
GET /api/users/124
{"id":124,"name":"佐藤花子","email":"hanako@example.com"}
他人(佐藤花子さん)の情報が返ってきました。ログインし直してもいませんし、特別な攻撃ツールも使っていません。URL の数字を1つ変えただけです。
CCT の教材でも、http://billpay.com/api/v1/cust/459 のように顧客 ID(custID)を URL で直接指定できる例が挙げられ、この値を総当たりすることで権限外のデータにアクセスできると説明されています(出典: CCT eBook 書籍262/PDF273-274)。まさに今の実演と同じ構図です。
図にすると、門番(Reference Monitor)が不在のまま Object が返っている状態です。
これは「水平権限昇格」
今回のように、同じ権限レベルの別ユーザーのリソースにアクセスできてしまうことを、水平権限昇格(horizontal privilege escalation)と呼びます(出典: CCT eBook モジュール02)。管理者権限を奪うような「垂直」の昇格ではなく、横並びのユーザー同士でデータをのぞき見できてしまう状態です。地味に見えて、個人情報の大量流出に直結する危険なパターンです。
なぜ穴は生まれるのか ── 「取得できる」は「見てよい」ではない
実演のコードを思い出してください。やっていたのは「ID でレコードを取ってきて、そのまま返す」だけでした。
ここで大事なのは、find($id) でレコードを取得できたことは、そのユーザーがそれを見てよいことを意味しないという点です。データベースは「その ID のレコード」を素直に返すだけで、「これは今ログインしている人のものか」までは判断しません。
CCT では IDOR を、「API の引数にオブジェクトの直接参照が使われ、アクセス制御が課されていないため、パラメータ値の総当たりで権限外データにアクセスできる」欠陥として定義しています(出典: CCT eBook 書籍263/PDF274)。IDOR は、インジェクションやセッション処理の不備などと並ぶ代表的な API 攻撃の一つとして整理されています(出典: CCT eBook モジュール02)。ポイントは「アクセス制御が課されていない」ところ、つまり門番(Reference Monitor)がいないことです。
さきほどの図でいえば、Subject が Object に手を伸ばしたときに、本来は門番が「あなたのものですか?」と確認するはずでした。IDOR はその門番を素通りしている状態です。伏線として置いた門番は、ここで穴の正体として回収されます。
用語の系譜: IDOR / BOLA / Broken Access Control
同じ穴が、時代や文脈によって別の名前で呼ばれます。整理しておきます。
- IDOR / Missing Function Level Access Control: OWASP Top 10 の 2013 年版には、Insecure Direct Object References と Missing Function Level Access Control という項目が独立して存在していました(出典: CCT eBook 書籍1127/PDF1138)。これらは 2017 年版で Broken Access Control(A5:2017)に統合され、2021 年版ではその Broken Access Control が1位に上昇しました。現在も A01:2021 の説明の中に IDOR が例として残っています(出典: https://owasp.org/Top10/2021/A01_2021-Broken_Access_Control/)。
- A01:2021 Broken Access Control: OWASP Top 10(Web)の 2021 年版では、Broken Access Control が 2017 年版の5位から1位に上昇しました。IDOR(一意な識別子を渡して他人のアカウントを閲覧・編集する例)が明記され、CWE-639(Authorization Bypass Through User-Controlled Key)や CWE-284(Improper Access Control)など計34の CWE がマッピングされています(出典: https://owasp.org/Top10/2021/A01_2021-Broken_Access_Control/)。
- API1:2023 Broken Object Level Authorization(BOLA): OWASP API Security Top 10 の 2023 年版では、エンドポイントに渡すオブジェクト ID を改ざんし、権限のないオブジェクトにアクセスする欠陥が API1(最上位) に位置づけられています。これはオブジェクト単位の認可の失敗そのものです(出典: https://owasp.org/API-Security/editions/2023/en/0xa1-broken-object-level-authorization/)。
呼び名は違っても、根っこは同じ「オブジェクト単位の認可の欠落」です。API を書くなら BOLA(API1:2023)を、Web 全般なら Broken Access Control(A01:2021)を、それぞれ最重要級の脅威として意識しておくとよいです。
認可の4分類と「明示的な認可」
認可には種類があります。CCT では次の4つに分類されています(出典: CCT eBook 書籍513-514/PDF524-525)。
- 集中型(Centralized): 認可の判断を1箇所に集約する。
- 分散型(Decentralized): 各所で個別に判断する。
- 暗黙的(Implicit): 明示的な確認をせず、暗黙の前提で通す。
- 明示的(Explicit): 「これは本人のものか」をコードで明示的に確認する。
IDOR は、「取得できたのだから見てよいはず」と暗黙的に判断してしまっている状態だと言い換えられます。対策の方向性はシンプルで、暗黙をやめて明示的に確認すること、そして分散させずに集中型で1箇所に集約することです。次章で、これをフレームワークのコードに落とし込みます。
フレームワークでどう守るか ── 自前実装 vs 集中管理
ここからは実装です。まず前提を明記しておきます。
- 以降のコードは認証(ログイン)は通過済みとします。認証していないユーザーは別途はじく前提です。
- ユーザーテーブルは
users.idを主キーとします。 - 所有判定は「対象ユーザー自身か」を
$user->id === $model->idで行います。所有リソース(投稿など)の場合は$resource->user_id === $user->idと同じ考え方です。 - コードは説明のためのスニペット抜粋であり、そのままコピペして動作することを保証するものではありません。
before(穴あり)から after(修正後)へ、差分でどこがポイントかを見ていきます。
FuelPHP 1.x: 行レベル認可は自前になりがち
まずレガシーな FuelPHP 1.x です。FuelPHP の Auth パッケージには、認証を担う Login ドライバに加えて、Group ドライバや ACL ドライバがあります。グループ / ロールベースの ACL 認可(「このグループにこの権限を与える」)はきちんと用意されています(出典: https://fuelphp.com/docs/packages/auth/intro.html)。
ただし、オブジェクト(行)単位の認可 ── モデルごとの Policy に相当する仕組みは標準では持ちません。「このレコードは"この"ログインユーザーのものか」という所有チェックは、コントローラでの自前実装に依存しがちです。ここを書き忘れると、次のように IDOR が生まれます。
// fuel/app/classes/controller/api/users.php (FuelPHP 1.x)
class Controller_Api_Users extends Controller_Rest
{
// GET /api/users/{id} ※ログイン必須(認証)は通過済みとする
public function get_view($id = null)
{
$user = Model_User::find($id); // ID で取得するだけ
// 「これはあなたのものか」を確認していない → IDOR
return $this->response($user);
}
}
Model_User::find($id) は、渡された ID のレコードを素直に返します。グループの ACL 認可を設定していても、それは「この API を叩ける役割か」までしか見ておらず、「その1件が本人の行か」は見ていません。だから他人の ID を渡せば他人のデータが返ります。FuelPHP のような FW では、この所有チェックを自分で足す責任が開発者側にあることを意識する必要があります。
では、どう直すのでしょうか。恒久的な推奨形を先に言うと、この所有チェックをコントローラのあちこちに散らさず、共通の認可ヘルパやベースコントローラの1箇所に集約することです(集約の設計は後述します)。とはいえ、まずは目の前の穴を止めたいはずです。そこで応急処置(最小の止血)として、取得したレコードが「ログイン中の本人のものか」を、返す前にコントローラ内で明示的に確認します。FuelPHP には行レベル認可の仕組みが無いので、この所有チェックは自前で書きます。
after(所有チェックを追加 = 他人なら 403):
// fuel/app/classes/controller/api/users.php (FuelPHP 1.x)
class Controller_Api_Users extends Controller_Rest
{
// GET /api/users/{id} ※ログイン必須(認証)は通過済みとする
public function get_view($id = null)
{
$user = Model_User::find($id);
if (empty($user)) {
return $this->response(null, 404); // レコードが無い
}
// Auth::get_user_id() は array(driver_id, user_id) を返す。[1] がログイン中ユーザーの id
$current_user_id = Auth::get_user_id()[1];
// 所有チェック: 取得したレコードが「ログイン中の本人」か
if ((int) $user->id !== (int) $current_user_id) {
return $this->response(array('error' => 'Forbidden'), 403); // 他人 → 403
}
return $this->response($user);
}
}
FuelPHP の Controller_Rest::response() は、第2引数に HTTP ステータスコードを取ります(出典: https://fuelphp.com/docs/general/controllers/rest.html)。ログイン中ユーザーの id は Auth パッケージの Auth::get_user_id() から得られます。このメソッドは array(driver_id, user_id) を返すため、[1] がユーザーの id です(未ログインなら false ですが、ここでは認証済みが前提。出典: https://fuelphp.com/docs/packages/auth/types/login.html)。所有者でなければ 403 を返し、他人のデータには一切触れさせません。なお、他人にリソースの存在すら知られたくない場合は、403 の代わりに 404 を返す流儀もあります。
ただしこの所有チェックは、あくまで各コントローラに手で書いた止血です。エンドポイントが増えるほど書き忘れのリスクが上がります。恒久策は次節の集約で示します。
他人の id で叩くと、次のように 403 が返ります。
HTTP/1.1 403 Forbidden
{"error":"Forbidden"}
Laravel 13.x: Gate / Policy で1箇所に集約
一方 Laravel(13.x)には、認可を集約する仕組みが標準で用意されています。Gate と Policy の2方式があり、モデルやリソースごとの認可ロジックは Policy に集約するのが定石です(出典: https://laravel.com/docs/13.x/authorization)。
Policy は次のコマンドで生成できます。
php artisan make:policy UserPolicy --model=User
生成された Policy に、「対象ユーザーを閲覧してよいか」を明示的に書きます。
// app/Policies/UserPolicy.php
namespace App\Policies;
use App\Models\User;
class UserPolicy
{
// 認証済みユーザー($user)が対象ユーザー($model)を閲覧してよいか
public function view(User $user, User $model): bool
{
// 自分自身だけ閲覧可(明示的認可)
return $user->id === $model->id;
}
// 所有リソースの場合は $resource->user_id === $user->id と同じ考え方
}
これで「本人だけ閲覧可」という認可ルールが1箇所に明示されました。あとはコントローラからこの Policy を呼び出します。
Route Model Binding は「認可しない」
ここが誤解の多いところです。Laravel の Route Model Binding(RMB) は、URL の ID からモデルインスタンスを自動で解決して注入してくれる便利な機能ですが、認可はいっさい行いません。あくまで「ID → インスタンス」の解決だけです(出典: https://laravel.com/docs/13.x/routing、https://laravel.com/docs/13.x/authorization)。
RMB を使っているだけで安全になった気がしてしまいますが、次の before はまさに IDOR です。
before(RMB のみ・認可なし = IDOR):
// routes/api.php: Route::get('/users/{user}', [UserController::class, 'show']);
namespace App\Http\Controllers;
use App\Models\User;
class UserController extends Controller
{
// Route Model Binding は ID→インスタンス解決のみ(認可しない)
public function show(User $user)
{
// 認可チェックが無い → 他人の $user も返る = IDOR
return $user;
}
}
show(User $user) と書くと、Laravel が URL の ID からユーザーを解決して $user に入れてくれます。便利ですが、解決しただけです。他人の ID を渡せば他人の $user が入り、そのまま返ってしまいます。FuelPHP の例と本質的に同じ穴です。
これを塞ぐには、1行 Gate::authorize() を足すだけです。
after(Gate::authorize を追加 = 他人なら 403):
// routes/api.php: Route::get('/users/{user}', [UserController::class, 'show']);
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Support\Facades\Gate;
class UserController extends Controller
{
// Route Model Binding は ID→インスタンス解決のみ(認可しない)
public function show(User $user)
{
// ここで初めて Policy が走り、他人なら AuthorizationException → 403
Gate::authorize('view', $user);
return $user;
}
}
// ルート側で守るなら: Route::get('/users/{user}', ...)->can('view', 'user');
before との差分は、use 文とあわせても2行、認可の判断そのものは Gate::authorize() の1行だけです。
use App\Models\User;
+use Illuminate\Support\Facades\Gate;
// ...
public function show(User $user)
{
+ Gate::authorize('view', $user); // 他人なら AuthorizationException → 403
return $user;
}
Gate::authorize('view', $user) を呼ぶと、さきほど書いた UserPolicy::view() が走ります。本人なら true で通過し、他人なら AuthorizationException が投げられて自動的に 403 になります。認可ロジックは Policy に集約されているので、コントローラ側は「認可を通す」という意思表示を1行するだけで済みます。
他人の id で叩くと、AuthorizationException が 403 に変換され、次のようなレスポンスが返ります(JSON をリクエストした場合)。
HTTP/1.1 403 Forbidden
{"message":"This action is unauthorized."}
This action is unauthorized. は Laravel が付与する既定のメッセージで、Policy 側で Response::deny('...') を返せば任意の文面に差し替えられます(出典: https://laravel.com/docs/13.x/authorization)。
ルート定義側で守りたい場合は、can 認可ミドルウェア(->can('view', 'user'))でも同じことができます(出典: https://laravel.com/docs/13.x/authorization)。どちらにしても、明示的な認可を1箇所に集約するという発想は共通です。
認可が薄い FW / レガシーでどう守るか
FuelPHP のように行レベル認可の仕組みを標準で持たない FW でも、考え方は同じです。認可の判断をコントローラのあちこちに散らさず、1箇所に集約することを目指します。
具体的には、次のような一般化した設計に落とせます。
- 「このユーザーはこのリソースの所有者か」を判定する共通の認可チェック(サービスクラスやヘルパー)を1つ用意する。
- 各コントローラは、リソースを返す前に必ずその共通チェックを呼ぶ。
- 呼び忘れを防ぐため、チェックを通っていないレスポンスは返さない運用ルールにする。
これは CCT でいう明示的かつ集中型の認可(前述の4分類)を、仕組みの薄い FW で手作りしているだけです。フレームワークが Policy を用意してくれているなら乗る、なければ同じ役割の層を自分で作る、という判断になります。
脅威 → 対策マッピング
ここまでの脅威と対策を1枚に整理します。上の3つは同じ穴の別名で、下の2つは関連する別概念ですが、いずれも対策の方向性は共通です。
| 脅威(呼び名) | 出典 | 原因 | 対策 |
|---|---|---|---|
| IDOR(安全でない直接オブジェクト参照) | CCT / OWASP 2013 | オブジェクト単位の認可が無く、ID 総当たりで権限外データに到達 | 取得後に「本人のものか」を明示的に確認する |
| BOLA(API1:2023) | OWASP API Security Top 10 | エンドポイントに渡す ID を改ざんし権限外オブジェクトへアクセス | オブジェクト単位の認可を必ず実行する(Gate / Policy など) |
| Broken Access Control(A01:2021) | OWASP Top 10 | アクセス制御の不備(IDOR を内包)。2021年版で1位 | 認可をデフォルト拒否・集中型・明示的に設計する |
| 水平権限昇格 | CCT モジュール02 | 同一権限レベルの別ユーザーのリソースにアクセスできる | 所有者チェック($user->id === $model->id 等)を1箇所に集約 |
| 認証と認可の混同 | CCT eBook 書籍513/PDF524 | 認証(本人確認)で止まり、認可(Object 単位の確認)をしていない | 認証=本人確認まで/認可=別途 Object 単位で確認する |
共通する対策は1つに集約されます。取得できたことに満足せず、返す前に「これはこのユーザーのものか」を明示的に確認する。その判断を1箇所にまとめる。これだけです。
まとめ ── 認証 ≠ 認可。取得できる ≠ 見てよい
最後に、この記事の要点を振り返ります。
- 認証が確認するのは「あなたが誰か」までです。「その操作をしてよいか」は認可の仕事で、認証を通した後こそが認可の主戦場です(認証 ≠ 認可)。
-
find($id)で取得できたことは「見てよい」ことを意味しません。ID を書き換えるだけで他人のデータに届くのが IDOR で、OWASP では BOLA(API1:2023)や Broken Access Control(A01:2021)として最重要級に位置づけられています(取得できる ≠ 見てよい)。 -
認可は1箇所に明示的に集約します。Laravel なら Policy に書いて
Gate::authorize()で呼ぶ、仕組みの薄い FW なら同じ役割の集約層を自作する。Route Model Binding は解決するだけで認可はしないことに注意します。
ちょっと前の私がいちばん助かったであろうポイントは、「find($id) できた = OK ではない」という一点でした。ここに気づけば、自分のコードのどこに門番を立てるべきかが見えてきます。
Next action: 認可テストを1本書く
理解を定着させる最短ルートは、認可のテストを1本書くことです。おすすめは次のテストです。
- ユーザー A でログインした状態で、ユーザー B のリソースの ID を指定してエンドポイントを叩く。
- レスポンスが 403(Forbidden) になることを確認する。
このテストが赤いままなら、あなたのコードには IDOR が残っています。逆にこのテストが通れば、少なくともそのエンドポイントには門番が立っています。まずは1本、書いてみてください。
あわせて読みたい
- 認証そのものをもう少し深掘りしたい方向けに、認証の復習記事を用意しています: その多要素認証、どの攻撃に効いてますか? ── 脅威で認証を整理し直す【CySec復習ログ#6】
- 本シリーズの第2回では、インジェクション系の脆弱性と SSRF を扱う予定です(近日公開予定)。公開後にこの箇所へリンクを差し替えます。
参考
- OWASP API Security Top 10 ── API1:2023 Broken Object Level Authorization: https://owasp.org/API-Security/editions/2023/en/0xa1-broken-object-level-authorization/
- OWASP Top 10 ── A01:2021 Broken Access Control: https://owasp.org/Top10/2021/A01_2021-Broken_Access_Control/
- Laravel 13.x Authorization(Gate / Policy / can ミドルウェア): https://laravel.com/docs/13.x/authorization
- Laravel 13.x Routing(Route Model Binding): https://laravel.com/docs/13.x/routing
- FuelPHP 1.x Auth パッケージ: https://fuelphp.com/docs/packages/auth/intro.html
- CCT 日本語 eBook ── モジュール02(情報セキュリティ攻撃・API 攻撃 / IDOR: 書籍262-263・PDF273-274)、モジュール04(認証・認可: 書籍473-514・PDF484-525)