1-1. 認証と認可の基本 - AuthN と AuthZ を混同しない

所要時間: 30-45分 ゴール: 認証(AuthN)と認可(AuthZ)の違いを明確に説明できる。主要な認証方式・認可方式の用途とトレードオフを理解する コミット内容: 自分のサービス(架空でOK)の認証/認可方針メモを ~/learn/security/day01_auth_design.md に残す


前章とのつながり

このレッスンの位置づけ

セキュリティ章の 最初の扉。以降のすべて(パスワード保存、HTTPS、JWT、CSRF、認可設計)は「誰がアクセスし、何を許すか」という本章の枠組みの上に積み上がる。

ここで AuthN と AuthZ の境界が曖昧なまま進むと、後続のレッスンが全部ぼやけて入ってくる。最初の1時間で土台を固めるのがコスパ最高。

実害シーン: 認証/認可の事故は「億単位」で起きる

  • First American Financial (2019): URL の番号を ?docId=123 から ?docId=124 に書き換えるだけで他人の住宅ローン書類が見える状態だった → 8.85億件流出。これは認可(AuthZ)の欠陥
  • Optus (2022): 認証なしの API エンドポイントを叩くだけで全顧客の個人情報取得可能 → 約1000万件流出、CEO 辞任
  • メルカリ (2017): 一時 Cookie の取り扱いミスで他人のアカウントに「ログイン状態」で入れる事象 → 緊急サービス停止

これらはすべて 「ログインさせる仕組み」と「許可する仕組み」を分けて設計できていなかった ことが根本原因。本章はその境界線を引く回。


大前提: なぜここから始めるか

セキュリティの話題の9割は 「誰がアクセスしているか」「その人に何を許すか」 をめぐる議論です。にも関わらず、現場で一番混同されるのが「認証」と「認可」。

  • 「ログインさせる」のは認証(Authentication / AuthN
  • 「ログインした人に管理画面を開かせる」のは認可(Authorization / AuthZ

これがゴチャゴチャしたまま設計すると、

  • 管理画面のURLを知っていれば一般ユーザーでも入れる(認可が抜けてる)
  • パスワード認証は通すのに、強制ログアウトの仕組みがない(セッション設計が破綻)
  • OAuthで「ログイン」と「権限委譲」を混ぜて誤実装

といった事故が起きる。OWASP Top 10 の A01(Broken Access Control)と A07(Authentication Failures)は毎年上位に居座っていて、これらは「AuthN と AuthZ を分けて設計できていない」が根本原因です。

このレッスンでは 架空の SaaS「TaskNote」(社内タスク管理ツール)にログイン機能を実装する という想定で、用語と方式を整理する。


セッション①: 認証と認可は何が違うか(25-30分)

0. 録画&メモ準備

mkdir -p ~/log ~/learn/security
script ~/log/security_day01.log

1. 認証(Authentication / AuthN)とは何か

「あなたは誰ですか?」を確認するプロセス。本人確認。

ユーザー: 「私は alice です。パスワードは hunter2 です」
   ↓
サーバー: パスワードDBと照合
   ↓
サーバー: 「OK、確かに alice さんですね」

認証の本質

「自称している身元」が正しいかを確かめる。「本人かどうか」しか興味がない

認証が成功すると、サーバーはそのリクエストに「これは alice だ」という識別子を結びつける。以降のリクエストでも alice として扱われる(セッション / トークン経由)。

認証は 必ずしも信頼できるとは限らない: 「自称 alice」がパスワードを知っていただけで、本物の alice が漏洩させた可能性もある。だから多要素(MFA)などで強化する。

認証の3要素(3 factors)

認証の根拠は伝統的に3つに分類される:

  1. 知識要素(Something you know): パスワード、PIN、秘密の質問
  2. 所持要素(Something you have): スマホ、ハードウェアトークン、ICカード
  3. 生体要素(Something you are): 指紋、顔、虹彩

多要素認証(MFA / 2FA): これらのうち 2つ以上の異なる要素 を組み合わせる。パスワード(知識)+SMS(所持)が古典的MFA。

「パスワード + 秘密の質問」は両方とも知識要素なので 多要素にならない。これがよくある誤解。

2. 認可(Authorization / AuthZ)とは何か

「この人に X をさせていいか?」を判断するプロセス

alice として認証済みのリクエスト: 「ユーザー bob のメール一覧を見せて」
   ↓
サーバー: alice は bob のメールにアクセスできるか?
   ↓
サーバー: 「alice は管理者ではないので NG。403 を返す」

認可の本質

「身元が確認できた」あとに 「その人が何をできるか」 を決める。

認可は 必ず認証の後に行う: 誰だか分からないと「何を許すか」も決まらない。

逆に 認証を通したから何でも許す は重大な事故。多くのサービスは「ログインさせたら勝ち」と勘違いしている。

認証成功 = 全権限OK、ではない

「ログインできた」と「管理画面が見られる」は別問題。ログインしたユーザーが偶然 /admin を叩いたら入れちゃった、というのが A01 Broken Access Control の典型パターン。

認可チェックは 各エンドポイントごと に独立して行う必要がある。

3. 比較表で覚える

観点認証 (AuthN)認可 (AuthZ)
問いあなたは誰?何をしていい?
結果ユーザーID / セッション許可 / 拒否
失敗時HTTP401 Unauthorized403 Forbidden
タイミングログイン時、リクエスト到着時各API呼び出し時
実装場所認証ミドルウェア、SSO各ハンドラ、ポリシーエンジン
パスワード照合、JWT検証「このユーザーは admin か?」

HTTPステータスの罠

仕様上は「401 = 認証失敗」「403 = 認可失敗」だが、現場では混同して使われている

  • 401: そもそも認証情報が無い / 無効(再ログインさせるべき)
  • 403: 認証はできてるが、このリソースを見る権限が無い

「ログインしてください」を 403 で返している API は気持ち悪い。コードレビューで指摘ポイント。

4. 「TaskNote」での具体例

架空サービス TaskNote では:

機能認証認可
ログインページ表示不要不要
ログイン処理する(パスワード照合)不要
自分のタスク一覧必須ログイン済みなら全員OK
他人のタスク一覧必須チーム内のみOK
管理画面(全社のタスク)必須管理者ロールのみ
パスワード変更必須本人のみ(他人のは変えられない)

設計のコツ

エンドポイント設計の段階で 「この URL は誰がアクセスできる?」を表にする

この表が雑だと実装も雑になる。雑な実装 = 認可バグ = 個人情報漏えい。


セッション②: 認証方式と認可方式のカタログ(25-30分)

5. 主要な認証方式

パスワード認証

ユーザー: ID + パスワード送信
サーバー: ハッシュ化したパスワードとDB照合

パスワード認証の本質

一番古典的で、一番油断ならない方式。実装の99%は「パスワードをどう保存するか」「どう照合するか」 にかかっている。

ハッシュ化、salt、bcrypt/argon2 などの詳細は次レッスン 1-2 パスワードハッシュ で扱う。

ユースケース: ほぼすべてのWebサービスの基本認証 落とし穴: 平文保存(論外)、SHA-256そのまま保存(弱い)、レート制限なし(ブルートフォース食らう)

SSO(Single Sign-On)

ユーザー: Google でログイン
   ↓
TaskNote: Google に「この人を認証してください」と委譲
   ↓
Google: 認証してトークンを返す
   ↓
TaskNote: トークンを検証して「この人は alice@example.com です」と信頼

SSO(シングルサインオン)の本質

認証を 外部のID Provider(IdP)に委譲する 仕組み。Google / Microsoft / Okta などが IdP として認証を代行してくれる。

ユーザー側: パスワードを覚える数が減る、サービスごとに作らなくていい サービス側: パスワード保存・リセットなどの 責任を負わなくて済む

裏で動くプロトコル

  • OAuth 2.0: 認可フレームワーク(本来は「権限委譲」のための仕様)
  • OpenID Connect (OIDC): OAuth 2.0 の上に認証機能を載せたもの。「Googleでログイン」は実態として OIDC
  • SAML: エンタープライズ向け(古い)。Okta、社内システムでまだよく見る

ユースケース: 社内ツールで Google Workspace アカウントを使い回す、コンシューマ向けで「Twitterでログイン」を提供する 落とし穴: SSO に頼り切るとIdP障害で全社業務が止まる(Okta障害で社内ツール全滅、は2022年頃ニュースになった)

MFA(多要素認証 / Multi-Factor Authentication)

ステップ1: パスワード入力 → 通る
ステップ2: スマホアプリ(Google Authenticator など)の6桁コード入力 → 通る
   ↓ 両方OKで認証成功

MFA の本質

「パスワードを知っている」だけでは入れず、もう一つの要素(スマホを持っている、生体)を要求する。パスワード漏洩しても突破されにくくなる。

方式

  • TOTP(Time-based One-Time Password): Google Authenticator、Authy など。30秒ごとに変わる6桁
  • SMS OTP: 携帯にSMSで送る。今は非推奨(SIMスワップ攻撃で乗っ取られる)
  • WebAuthn / Passkey: 公開鍵暗号ベース、フィッシング耐性が高い。次世代の本命
  • ハードウェアキー: YubiKey などUSBデバイス

ユースケース: 管理者アカウント、金融サービス、社内SSO(社内ツールは全部MFA必須にすべき落とし穴: MFA 必須にしたら、リカバリーフロー(端末紛失時の救済)も設計しないと地獄。バックアップコード発行 + ヘルプデスク対応の体制必要

Passkey は今後の主流

2024年以降、Apple / Google / Microsoft が本格推進。パスワード不要 + 生体認証 + フィッシング耐性 の三拍子。

新規サービスを設計するなら最初から WebAuthn / Passkey を視野に入れる。

生体認証

生体認証は「ローカル」が原則

Face ID / Touch ID は 端末内 で照合される。生体データがサーバーに送られることは無い(少なくともAppleの仕組みでは)。

サーバーから見ると「端末で生体認証が通った」というシグナルが届くだけ。実態は WebAuthn / Passkey の MFA要素として組み込まれることが多い。

落とし穴: 「生体は最強」ではない。指紋は変更できないので、漏洩したら一生使えなくなる。サーバーに生体データそのものを送る設計は絶対にしない。

トークン認証(API Key、JWT)

トークン認証の本質

ログイン直後にサーバーが発行する「身分証」みたいな文字列。それを以降のリクエストで毎回提示する。

2つの代表的形式

  • 不透明トークン(opaque token): ランダム文字列。サーバー側DBで「このトークン → alice」と紐付け管理
  • JWT(JSON Web Token): 中身に情報を持ったトークン。署名付きで改ざん検知できる
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhbGljZSJ9.xxx

ユースケース: モバイルアプリ、SPA(フロントエンドからAPI叩く構成)、サービス間通信 落とし穴: JWT は トークン無効化が難しい(漏洩しても期限切れまで使えてしまう)。Cookie の HttpOnly + SameSite で守るほうが安全なケースも多い。詳細は後の章で

6. 認可方式の代表選手

ロールベース(RBAC: Role-Based Access Control)

ユーザー alice → ロール「admin」
ユーザー bob   → ロール「member」

「admin はすべて操作できる」
「member は自分のタスクのみ操作できる」

RBAC の本質

「役割(ロール)」に権限をまとめ、ユーザーにロールを付与する

ユーザーごとに細かい権限を設定するのではなく、「admin」「editor」「viewer」のような役割を定義して使い回す。90%のサービスはこれで十分

ユースケース: SaaS の管理者/一般ユーザー区分、社内ツールの部署別アクセス 落とし穴: ロールが増えすぎる「ロール爆発」。「営業部の中で関東チームだけ閲覧可」みたいな細かい条件をロールで表現しようとすると地獄

属性ベース(ABAC: Attribute-Based Access Control)

ルール: 「ユーザーの部署 == リソースの所有部署」ならアクセス可
ルール: 「現在時刻 ∈ 09:00-18:00」かつ「アクセス元IP ∈ 社内」ならアクセス可

ABAC の本質

ユーザー属性 + リソース属性 + コンテキスト を条件式で評価する。RBAC より柔軟だが複雑。

AWS IAM ポリシーは ABAC に近い。「タグ team=blue がついたインスタンスのみ操作可」のような書き方ができる。

ユースケース: 大企業の細かい権限制御、コンプライアンス要件が厳しい業界(金融・医療) 落とし穴: ポリシーが複雑になりすぎてレビュー不能になる。最初から ABAC を導入するのは過剰設計の典型

RBAC と ABAC の使い分け

  • まず RBAC で始める
  • ロールで表現しきれない条件が増えてきたら ABAC を部分的に導入する
  • 詳細は Level 2-6 の認可深掘り回で扱う(予定)

7. 脅威モデル: 攻撃者は誰か、何を守るか

実装方式を決める前に 「誰から、何を、どう守るか」 を整理する。これを「脅威モデリング(Threat Modeling)」と呼ぶ。

脅威モデリングの簡易版(STRIDE)

Microsoftが提唱した分類。脅威を6つのカテゴリで網羅的に洗い出す:

意味認証/認可との関係
Spoofingなりすまし認証で防ぐ
Tampering改ざん整合性チェック・署名
Repudiation否認監査ログ
Information Disclosure情報漏洩認可・暗号化
Denial of Serviceサービス妨害レート制限
Elevation of Privilege権限昇格認可の堅牢性

使い方: 設計レビューで「この機能に対する S/T/R/I/D/E はそれぞれ何?」と問う。脳内チェックリストとして優秀。

TaskNote の脅威モデル(演習)

自分のメモに以下を埋めてみる:

  • 守りたい資産: ユーザーのタスク内容、メールアドレス、パスワードハッシュ
  • 想定攻撃者:
    • 外部の野良攻撃者(自動ボット)
    • 元従業員(権限剥奪後もアクセスを試みる)
    • 内部の悪意あるエンジニア
  • 想定攻撃シナリオ:
    • パスワードリストでブルートフォース
    • SQL Injection でDB直接アクセス
    • 他人のタスクIDを推測してURL直叩き(IDOR)
  • 対策:
    • bcrypt + レート制限 + MFA
    • prepared statement + 入力検証
    • 各エンドポイントで「このリソースは自分のものか?」をチェック

8. 「ログイン機能を実装する」設計レビュー観点

実装に入る前のチェックリスト:

ログイン機能の最低要件

  • パスワードは bcrypt / argon2 で保存(平文・SHA-256単体は論外)
  • ログイン試行回数制限(5回失敗で15分ロック等)
  • パスワード強度ポリシー(最低8文字、辞書攻撃対策)
  • HTTPS 必須(パスワードを平文ネットワークに流さない)
  • セッションIDは推測不能(暗号学的乱数)
  • セッション固定攻撃対策(ログイン後にセッションID再生成)
  • ログアウト機能(サーバー側でセッション破棄)
  • パスワードリセットフロー(メール経由、ワンタイムトークン)
  • 監査ログ(誰がいつログインしたか)
  • MFA オプション(管理者は必須)

練習課題

# 1. 自分のメモ用に空ファイル作成
touch ~/learn/security/day01_auth_design.md
 
# 2. 以下を埋める
# - 自分の関わるサービス(実在 or 架空)の名前
# - 守りたい資産トップ3
# - 想定する攻撃者トップ3
# - 認証方式の選択(パスワード / SSO / MFA の組合せ)
# - 認可方式の選択(RBAC / ABAC)
# - 設計の弱点として懸念していること

設計メモのテンプレ

# TaskNote 認証/認可設計メモ
 
## 守りたい資産
1. ユーザーのタスク内容(機密度: 中)
2. メールアドレス(機密度: 中)
3. 認証情報(パスワードハッシュ)(機密度: 高)
 
## 認証方式
- 一般ユーザー: メール+パスワード(bcrypt)
- 管理者: 上記 + TOTP MFA 必須
- 将来: Google SSO を追加検討
 
## 認可方式
- RBAC: admin / member / guest の3ロール
- リソースアクセス: 「自分のチームのタスクのみ」を全エンドポイントでチェック
 
## 既知の懸念
- パスワードリセットフローのトークン有効期限を未決
- JWT 利用するか、セッション Cookie にするか未決

締め: 振り返り(10分)

1. セッション録画を終了

exit

2. 今日の発見(このノートに追記)

- 「認証と認可の違い」を3行で説明できるか書いてみる:
- 自分が普段使っているサービスで、MFAを有効にしていないものは?:
- 脅威モデルを書いてみて気づいた弱点:
- 明日やりたいこと:

チェックリスト

  • 「認証」と「認可」を1分で口頭説明できる
  • HTTP 401 と 403 の使い分けを言える
  • 認証の3要素(知識/所持/生体)を挙げられる
  • パスワード/SSO/MFA/トークンの違いを表で書ける
  • RBAC と ABAC の違いを言える
  • STRIDE の6項目を見ながら自サービスを評価した
  • day01_auth_design.md に脅威モデルメモを残した

詰まった時のチートシート

用語1行説明
Authentication (AuthN)あなたは誰か確認する
Authorization (AuthZ)この人に X をさせていいか判断する
MFA異なる要素を2つ以上組み合わせる
SSO認証を外部 IdP に委譲
OAuth 2.0認可フレームワーク(権限委譲)
OIDCOAuth 2.0 + 認証層
JWT署名付きで中身を持ったトークン
RBACロールに権限を集約
ABAC属性で動的に判定
STRIDE脅威分類のチェックリスト
401認証情報が無い/無効
403認証OKだが認可NG

「実務OK」基準

  • AuthN と AuthZ を絶対に混同しない: コードレビューで他人が混同していたら指摘できる
  • 「ログインしたから何でも見える」を許さない: 各エンドポイントで認可チェックを入れる発想がある
  • MFA の本質を理解している: 「パスワード + 秘密の質問」が多要素ではない理由を言える
  • 設計段階で脅威モデルを考える: 後から塞ぐのではなく最初から守る

メタ認知: 自分の理解度を診断する

30秒セルフテスト

以下を 見ずに口頭で 答えられるか試す。詰まったら本文に戻る。

  1. 「認証」と「認可」を1文ずつで説明せよ
  2. パスワード+秘密の質問は「多要素」か? Yes/No と理由
  3. 401 と 403 の使い分けは?
  4. SSO の裏で動くプロトコルを2つ挙げよ
  5. STRIDE の S と E は何? 認証/認可とどう関係する?

2問以上詰まったら → セッション①と③(比較表)を再読。すべて即答できたら次章へ。

次のレッスン

1-2 パスワードハッシュ でパスワード保存の正しい方法(bcrypt / argon2 / salt / pepper)に踏み込む。今回「パスワードはハッシュ化」と言ったが、実は SHA-256 そのままではダメ。なぜ専用のアルゴリズムが要るのかを次回扱う。

1週間後にもう一度ここに戻る(間隔反復)

認証/認可の用語は 1週間後に薄れる。1-6 XSS まで終わったタイミングで、この章の「詰まった時のチートシート」表だけ眺め直すと記憶が定着する。