うつろい EC のマイページには、ユーザロールによって表示される機能が変わる UI がある。一般会員には「会員退会」ボタンだけ表示、管理者には「他ユーザを削除」ボタンも表示される。
フロントエンドは v-if="user.role === 'admin'" 等で表示制御している。しかしサーバ側の POST /api/admin/delete-user エンドポイントには認可チェックが無い。一般会員でも、開発者ツールから API を直接呼べば実行できてしまう。
うつろい EC のマイページには、ユーザロールによって表示される機能が変わる UI がある。一般会員には「会員退会」ボタンだけ表示、管理者には「他ユーザを削除」ボタンも表示される。
フロントエンドは v-if="user.role === 'admin'" 等で表示制御している。しかしサーバ側の POST /api/admin/delete-user エンドポイントには認可チェックが無い。一般会員でも、開発者ツールから API を直接呼べば実行できてしまう。
一般会員(UI には削除ボタンが表示されない)として、API を直接呼んで他ユーザを削除してください。
↑ 一般会員のあなたには「他ユーザを削除」ボタンは表示されません。これは UI 上だけの制御。
ブラウザの開発者ツールで JS を実行する想定。ボタンを押すと、UI を介さずに API リクエストを送信できます。
(まだ呼び出していません)
// フロント (Vue) — UI 制御だけで認可を実装したつもり
<button v-if="user.role === 'admin'" @click="deleteUser(targetId)">
削除
</button>
// サーバ (Express) — 認可チェックなし
app.post('/api/admin/delete-user', (req, res) => {
if (!req.session.user) return res.status(401).end();
// ★ admin かどうかのチェックがない
User.deleteById(req.body.user_id);
res.json({ status: 'ok' });
});
フロントエンドのコードはユーザのブラウザで動くので、攻撃者は完全に制御できる。UI 制御は UX 改善のためのものであって、セキュリティ機構ではない。サーバ側で必ず認可を実装する必要があります。
「直接 API 呼び出し」を押すだけで成功します。サーバ側のエンドポイントは認可チェックを行っていないため、一般会員のセッションでも管理者専用 API が実行できてしまいます。
これは Lab 02 と並ぶ「縦の認可」不備の典型例。フレームワークの認可ミドルウェアを使えば自動的にチェックされる場面で、開発者が「フロントで隠したから大丈夫」と省略してしまうケースが多い。