ai-driven-development legacy-migration blazor

「画面は動く」が一番危ない — 操作権限を UI / API の二重で守る

UI 側でボタンを隠しただけで安心していると、API を直接叩かれた瞬間に終わります。レガシー移行で踏みやすい権限制御の落とし穴と、二重防御をルール化した話です。

W
渡邊 賢

なぜ書いたか

VB系の業務アプリには、「特定の高権限ユーザーだけが押せるボタン」が結構な数あります。Blazorに移行するときに、UI側のボタン表示条件は割と素直に再現できるのですが、API側に同じ条件を入れ忘れる という事故を実際に踏みました。今回はその話と、それ以降にルール化した二重防御の話です。

何が起きたか

ある画面で、Tabごとに削除ボタンが付いていました。元実装では片方のTabの削除は「高権限ユーザー専用」でした。Blazor移植後にレビューを回したら、こう返ってきました。

P1: Tab2 の削除に UI / API 両方の権限制御が不足している。
     → 一般ユーザーが高権限者専用操作を実行可能。

UI側はボタン表示条件を見落としていて、一般ユーザーでもボタンが押せる状態でした。さらにAPI側にもロールチェックが入っていなかったので、仮にボタンを隠せたとしても、APIを直接叩けば誰でも削除できる、という状態です。

対策: 二重防御をデフォルトに

UIを隠しただけで満足すると、ほぼ確実にこのパターンを踏みます。なので、権限制御を入れるときは 必ず両方 を満たすようにルール化しました。

  • UIガード: ボタンの disabled / 非表示条件に権限フラグを入れる
  • API認可: コントローラ側でも同じ条件を強制する。直API呼び出しを想定して書く

Blazor側の例だと、こんな書き方になります。

@if (CanUseRestrictedDelete)
{
    <button @onclick="OnDelete">削除</button>
}

API側はコントローラのアクションでロール検査を入れ、UI側のフラグと 同じ判定式 を使います。判定がふたつの場所で別々に書かれていると、片方だけ修正されて差分が出るので、可能な限り共通化します。

わかったこと

  • UI側で権限を制御していても、それは 見えなくしているだけ で、防御していません
  • API側の認可ガードは、UI側のガードとは「目的が違う」ものとして両方あるべきです(UIは誤操作防止、APIは不正アクセス防御)
  • レビュー観点に「権限制御はUI / APIの両方にあるか」を 固定で入れる と、見落としが激減します

次にやること / 未解決の問題

  • 権限フラグの計算ロジックを共通モジュールに寄せる作業がまだ進んでいない。今は画面ごとに似たような条件式が散らばっている
  • 認可ロジックの自動テストはまだ薄い。最低でも「権限なしでAPIを直叩きしたら403」のテストを各エンドポイントに足したい
person

渡邊 賢

等差級数的Commit 運営 / ICD VIETNAM.LLC General Manager

AI駆動開発と段階的なレガシーモダン化をテーマに、日々の試行錯誤をこのブログに記録しています。

プロフィール詳細 arrow_forward

似たような課題に困っている方、一緒に考えませんか。

AI駆動開発・Vibe Coding・レガシーマイグレーションに関するご相談を受け付けています。