セキュリティ●●○○○

認可

Authorization ・ にんか

認証済みの相手に、この操作とこのデータが許されるかをリクエストごとに判断するプロセス。

✦ 30秒で試す — 航海「あなたは誰か」と「それをしてよいか」は、別の問いaliceの画面には何が出る?予想してみる

概要

認可(authorization)とは、認証によって本人確認が済んだ相手に対して、「この操作をしてよいか」を判断するプロセスです。管理者だけがユーザーを削除できる、自分の投稿だけ編集できる、経理部だけが請求データを見られる——アプリケーションの「権限」にまつわる設計は、すべて認可の話です。英語圏では AuthZ と略され、認証(AuthN)と対で語られます。

大事なのは、認証と認可が別の問いに答えているということです。認証は「あなたは誰か」を確かめ、認可は「その人に、この対象へのこの操作が許されているか」を判断します。ログインに成功した(認証済み)からといって、すべての操作が許されるわけではありません。逆に、認可の判断は「誰か」が分かっていることが前提なので、通常は認証の後に来ます。認可の判断には、主体(誰が)・操作(何を)・対象(どのデータに)の3つがそろっている必要があります。

認可は人間のユーザーだけの話ではありません。API を呼び出すアプリケーションにどこまでの操作を許すか、クラウド上のサービスがどのリソースにアクセスできるか(IAM のポリシー)、コンテナや Kubernetes のワークロードに何を許すか——現代のシステムは認可の判断だらけです。

なぜ生まれたか

コンピュータを複数人で共有するようになった瞬間から、「誰か」の確認だけでは足りなくなりました。全員が本人確認済みでも、学生が教授の成績ファイルを書き換えられてよいはずがありません。1960〜70年代のタイムシェアリングシステムは、ファイルごとに「誰が読めるか・書けるか」を定める仕組み(UNIX のパーミッションはその代表)を備え、ここで「本人確認」と「権限の判断」が別の関心事として分離されました。

この分離が決定的に重要になったのが Web と API の時代です。Web ではリソースが /orders/123 のような URL で名指しされ、その番号は利用者が自由に書き換えられます。つまりサーバは、リクエストのたびに「この人がこの番号のものに触ってよいか」を確かめ直さなければなりません。組織の人数とリソースが増えると、「誰に何を許すか」を個別に管理するのも破綻します。さらに「他人に自分の権限の一部だけを貸したい」という新しい要求も生まれました。たとえば写真プリントサービスに、自分のクラウドストレージの写真だけを読ませたい。パスワードを渡せば全権限を渡すことになってしまう。この「権限の限定的な委譲」の問題を解決するために生まれたのが OAuth です。

詳細

認可チェックの基本フロー

Web アプリケーションでの認可は、リクエストのたびに行われる判断です。サーバの入口には、順番の決まった2つの関門があると考えると整理しやすくなります。

リクエスト到着関門 1認証:誰かを特定できるかセッションやトークンを検証誰か不明401 Unauthorized未認証:誰か分からない認証済み対象リソースと操作を特定例:注文123の閲覧関門 2認可:この主体に操作が許されるかロール・所有者・ポリシーを照合拒否403 Forbidden認証済みだが権限がない許可リソースへの操作を実行
リクエストは認証・認可という2つの関門を順に通過して、初めて実行に至る

1つ目の関門は認証で、セッションの Cookie やトークンを検証して「誰か」を特定します。特定できなければ、HTTP のステータスコード 401 Unauthorized を返します。2つ目の関門が認可で、特定した主体が、リクエストが指す対象に対してその操作をしてよいかを照合し、許されなければ 403 Forbidden を返します。401 の名前が “Unauthorized” なのは歴史的な混乱で、意味的には「Unauthenticated」に近い——この紛らわしさ自体が、認証と認可の混同がいかに根深いかを物語っています。

IDOR — 2つ目の関門を忘れたサーバ

認可の不備は、Web アプリケーションで最も頻出する脆弱性のカテゴリです。OWASP Top 10 では「アクセス制御の不備(Broken Access Control)」が2021年版で1位になり、2025年版でも1位のままです。その代表例が IDOR(Insecure Direct Object Reference、安全でない直接オブジェクト参照)です。

手順を追ってみます。(1)alice はログインして、自分の注文ページ GET /orders/123 を開きます。ブラウザはセッションの Cookie を付けて送り、サーバは alice だと特定します。(2)alice はアドレスバーの 123 を 124 に書き換えて送ります。Cookie は同じなので、1つ目の関門は問題なく通ります。(3)ここでサーバが「ログインしているか」しか確かめていなければ、データベースから注文 #124 をそのまま引いて返します。#124 は bob の注文で、配送先の住所まで載っています。サーバの認証は何も間違っていません。「誰か」は正しく分かっています。抜けているのは「その注文の持ち主は誰か」との照合だけです。

下の部品で確かめてください。リクエストの番号をつまんで書き換えて送ると、「ログイン確認だけ」のサーバと「持ち主まで照合」するサーバで結果が変わります。Cookie を外すと、どちらの関門で止まるかも分かります。

⚡ 体験: 注文番号を書き換えて、2つの関門を試す
サーバの実装
注文API(サーバ): リクエストのたびに関門を通す① 認証Cookie → 誰か② 認可(実装されていない)注文DB#121carol本棚#122bobヘッドホン#123alice珈琲豆#124bob腕時計+住所#125aliceマグカップ#126dave処方薬ブラウザalice でログイン中送るリクエスト(番号はつまんで左右に動かせる)GET /orders/‹123›Cookie: session=alice ✕GET /orders/123これまでの応答まだ送っていません
見つけた応答 0 / 4(自分の注文・他人の注文・403・401)

あなたは alice としてログインし、自分の注文 #123 を見ています。送るリクエストの番号をつまんで左右にドラッグし(‹ › を押しても変わります)、124 に書き換えてから、リクエストのチップを注文APIへ運んでください。

対策は、対象を取り出すクエリそのものに持ち主の条件を入れることです。SELECT * FROM orders WHERE id = ? AND user_id = ? のように、「番号で引いてから持ち主を確かめる」のではなく「自分のものの中から番号で引く」形にしておけば、照合を書き忘れる余地が減ります。番号を推測しにくい UUID にするのは補助的な対策にすぎません。URL は履歴や共有で漏れるので、推測できなくても照合は必要です。

権限をどうモデル化するか

認可設計の中心は「誰に何を許すか」をどう表現するかです。最も素朴なのはユーザーに権限を直接ひも付ける方法ですが、人数が増えると管理不能になります。そこで主流になったのが RBAC(ロールベースアクセス制御)で、「管理者」「編集者」「閲覧者」のようなロールに権限をまとめ、ユーザーにはロールを割り当てます。「自分の投稿だけ編集できる」「同じ部署の文書だけ見られる」のように、対象や状況の属性に依存する判断は、属性をルールで組み合わせる ABAC(属性ベースアクセス制御)が得意とします。IDOR の対策である持ち主の照合も、「利用者の ID = 注文の user_id」という属性の比較です。実務では、骨格を RBAC で組み、細部を属性のルールで補う併用が多く、その設計とロール爆発の問題は RBAC の記事で詳しく扱います。

スコープとトークン — API 時代の認可

REST API の世界では、認可の情報をトークンに載せて運ぶ設計が一般的です。OAuth では、アクセストークンに「スコープ」(read:photos のような許可範囲)を持たせ、API はトークンの提示を受けてスコープの範囲内の操作だけを許します。JWT を使えば、ロールやスコープをトークン自体に署名付きで埋め込み、サーバ側の照会なしに検証できます(その代わり即時失効が難しい、というトレードオフがあります)。ただしスコープが答えるのは「この種類の操作をしてよいか」までで、「この注文は誰のものか」は答えません。スコープがそろっていても、対象ごとの持ち主の照合は別に必要です。クラウドの IAM も同じ発想の大規模版で、「どの主体が・どのリソースに・どの操作を」をポリシー文書で宣言します。

実務での落とし穴

典型的な失敗のひとつが「フロントエンドだけの制御」です。管理メニューを画面上で非表示にしても、API を直接叩けば操作できてしまうなら認可は存在しないのと同じです。UI の出し分けは体験のためのもので、防御は必ずサーバ側で行います。一覧 API では自分の分だけを返すのに、詳細・更新・削除の API で照合を忘れる、という「入口ごとの抜け」もよく起きます。

設計の指針は3つあります。デフォルト拒否(明示的に許可したもの以外は拒否する)、最小権限の原則(必要最小限の権限だけを与える)、そして認可の判定ロジックを各所に散らばらせず一箇所(ミドルウェアやポリシーエンジン)に集約することです。加えて、誰が何にアクセスし、何が拒否されたかをログとして残しておくことが、事故時の調査と権限設計の見直しの土台になります。403 が急に増えたら、誰かが番号を順に試している兆候かもしれません。

試問

あなたは alice としてネット通販にログインしています。送るリクエスト GET /orders/123 の注文番号(121〜126)と、ログインの印である Cookie の有無を変えて、リクエストのチップを注文API(サーバ)へ運べます。サーバの実装は「ログイン確認だけ」と「持ち主まで照合」から選べ、右の注文DB で各注文の持ち主が分かります。

✦ 命題挑戦中

持ち主まで照合するサーバに、1つ目の関門で止まるリクエスト・2つ目の関門で止まるリクエスト・両方を通って #123 以外の注文が返るリクエストを、それぞれ送れ

  • 「持ち主まで照合」のサーバで、1つ目の関門(認証)で止められる — 401
  • 「持ち主まで照合」のサーバで、2つ目の関門(認可)で止められる — 403
  • 「持ち主まで照合」のサーバから、#123 以外の注文を受け取る — 200
⚡ 体験: 2つの関門で、止まる場所を作り分ける
サーバの実装
注文API(サーバ): リクエストのたびに関門を通す① 認証Cookie → 誰か② 認可(実装されていない)注文DB#121carol本棚#122bobヘッドホン#123alice珈琲豆#124bob腕時計+住所#125aliceマグカップ#126dave処方薬ブラウザalice でログイン中送るリクエスト(番号はつまんで左右に動かせる)GET /orders/‹123›Cookie: session=alice ✕GET /orders/123これまでの応答まだ送っていません

あなたは alice としてログインし、自分の注文 #123 を見ています。送るリクエストの番号をつまんで左右にドラッグし(‹ › を押しても変わります)、124 に書き換えてから、リクエストのチップを注文APIへ運んでください。