0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

BrokenAccessControl(アクセス制御の不備)

0
Posted at

Broken Access Control を技術者として正しく理解する

〜「認証しているのに事故る」最も多い脆弱性〜

Broken Access Control(アクセス制御の不備)は、OWASP Top 10 で常に上位に登場する脆弱性です。
特定の言語やフレームワーク固有の問題ではなく、設計と思考の問題として発生します。

本記事は 初心者〜中級者の Web エンジニア を対象に、

  • Broken Access Control とは何か
  • なぜ頻発するのか
  • よくあるアンチパターン
  • なぜアンチパターンに陥るのか
  • 特に多い「画面操作前提」という思考

を整理します。

※ ソースコード例は理解しやすさのため Laravel(PHP)で記述しますが、
考え方自体はどの環境でも同じです。


Broken Access Control とは?

Broken Access Control とは、

ログインはしているが、本来許可されていない操作やデータに
アクセスできてしまう状態

を指します。

重要なのは「認証」と「認可」の違いです。

  • 認証(Authentication):あなたは誰か?本人確認(ログイン)
  • 認可(Authorization):あなたはそのリソース/操作に対する権限を持っているか?

例えば、

  • ログインできている → 認証OK
  • でも他人の注文を見られてしまう → 認可NG

Broken Access Control は、認可の失敗です。
ログインできているかどうかは、本質ではありません。


なぜ Broken Access Control は多発するのか?

理由はいくつもありますが、
実務で一番多い原因はこれです。

「ユーザーは画面の通りにしか操作できない」

という思い込みです。


アンチパターン①

「ログイン必須にしているから大丈夫」

Route::get('/orders/{id}', function ($id) {
    return Order::findOrFail($id);
})->middleware('auth');

何が問題か?

  • ログインしていれば、誰の注文でも閲覧できる
  • ID を変えるだけで他人のデータにアクセスできる

これを IDOR(Insecure Direct Object Reference:安全でない直接オブジェクト参照) と呼びます。
URLのIDを変えるだけで、本来アクセスできないデータにアクセスできてしまう脆弱性です。

なぜこのアンチパターンに陥るのか?

  • 「ログイン必須 = 安全」という思い込み
  • 認証と認可を無意識に混同している
  • 正常系テストでは必ず成功するため、危険に気づけない

アンチパターン②

「画面に出していないから使えない」

@if($user->is_admin)
    <a href="/admin/users">管理画面</a>
@endif

何が問題か?

  • URL を直接叩けば誰でもアクセスできる
  • 画面制御は UX の話であり、セキュリティではない

なぜこのアンチパターンに陥るのか?

  • 「画面に出ていない = 操作できない」という錯覚
  • フロントエンドで完結した気になる
  • サーバー側の責務を意識していない

【重要】アンチパターンに陥る一番多い理由

画面操作を前提にしてしまっている

Broken Access Control の原因は色々ありますが、
現場で圧倒的に多いのはこれです。

画面上ではこうなっているから大丈夫、という思考。

例えば、

  • 注文一覧には自分の注文しか表示されない
  • 注文詳細は一覧からクリックしたものしか見られない
  • だから他人の注文は見られないはず

という思い込みです。
image.png

※AIによって生成したイラストです

これは UI の制約
システムの制約だと勘違い しています。


なぜこの思考が生まれるのか?

① 画面は制限されているように見える

  • 表示される情報が限定されている
  • 操作できる導線が制御されている

そのため「この操作はできない」と錯覚します。
しかしそれは UI の話であって、サーバーの話ではありません。


② テストも画面操作しかしていない

  • テストケース = 画面操作
  • URL を直接叩くテストをしていない

結果として、

画面通りに使えば問題ない

という誤った成功体験だけが積み重なります。


③ 攻撃者は画面を見ていない

攻撃者は画面を見ません。

/orders/101
/orders/102
/orders/103

ID を変えて直接叩くだけです。

サーバー側で

  • このユーザーは、このデータを見てよいか

を判定していなければ、即アウトです。


正しい基本方針(フレームワーク非依存)

Broken Access Control を防ぐために重要なのは、

  • 画面や遷移を一切信用しない
  • すべてのリクエストを単体で評価する
  • 毎回「このユーザーはこれをしてよいか?」を判断する

という考え方です。


実装イメージ(考え方の一例)

パターン1: 明示的なチェック

public function show(Request $request, int $id)
{
    $order = Order::findOrFail($id);

    if ($order->user_id !== $request->user()->id) {
        abort(403);
    }

    return $order;
}

パターン2: Laravel Policy を使った実装

Laravel には認可を管理する仕組み(Policy)が標準で用意されています。

// app/Policies/OrderPolicy.php
class OrderPolicy
{
    public function view(User $user, Order $order): bool
    {
        return $user->id === $order->user_id;
    }
}

// Controller
public function show(Request $request, int $id)
{
    $order = Order::findOrFail($id);
    $this->authorize('view', $order);

    return $order;
}

Policy を使うことで、認可ロジックを一箇所に集約でき、
テストやメンテナンスがしやすくなります。

重要なのはコードの形ではなく、

  • 一覧を経由しなくても安全か
  • URL を直接叩かれても安全か

という視点です。


【注意】競合状態(Race Condition)にも気をつける

認可チェックには、もう一つ落とし穴があります。
それが 競合状態(Race Condition) です。

問題のあるコード

public function show(Request $request, int $id)
{
    $order = Order::findOrFail($id);

    // ここで認可チェック
    if ($order->user_id !== $request->user()->id) {
        abort(403);
    }

    // この間に order->user_id が変更される可能性
    // (別プロセスで所有者変更など)

    return $order;
}

何が問題か?

  1. データを取得
  2. 認可チェック
  3. データを使用

この間に、別のリクエストやバッチ処理でデータが変更される可能性があります。
これを TOCTOU(Time-of-check to time-of-use)問題 と呼びます。

対策

  • トランザクション内で取得とチェックを行う

  • 楽観的ロック(Optimistic Locking)を使う

  • WHERE 句で直接絞り込む

    // WHERE句で直接絞り込む例
    $order = Order::where('id', $id)
    ->where('user_id', $request->user()->id)
    ->firstOrFail();

この方法なら、取得とチェックが1つのクエリで完結します。


まとめ

Broken Access Control は、

  • 特定の技術の問題ではない
  • 高度な攻撃は不要
  • 最大の原因は「画面操作前提の思考」

です。

画面は UX を良くするためのもの。
セキュリティを保証するものではありません。

Broken Access Control に限ったことではないですが、
自分がやり方を知らない=誰もできない
ではないです。

自分はやり方知らないけど、もしこういうことがやられたら(できてしまったら) を常に意識することがセキュリティ対策の第一歩だと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?