Open5

Roadmap.sh 学習メモ

ふじしろふじしろ

Authentication

なぜ認証が必要か?どのような役に立っているのか?

  • 機密データを保護したい
  • 不正なアクセスを防ぎたい
  • 利用状況を追跡したい
  • リソースに対するアクセスのきめ細かな制御を行いたい

どのような手段があるか?

  • OAuth2.0
  • OIDC
  • API Key
  • JWT
  • Basic authentication
ふじしろふじしろ

SSO Single Sign-on

本質は「認証の一元化と認証結果の共有」

一組のid/passで複数のサービスにログインできる。
一度のログインで複数のサービスにシームレスにアクセスすることができる。

なぜSSOは生まれた?何の役に立っている?
以下のような課題があり、それを解決した。

  • 様々なサービスが生まれるにつれて大量のid/pass を管理する必要が生じた
  • サービスの行き来の度に都度ログインを求められるという手間が生じた
  • 管理の難しさからid/passの使い回しや弱いパスワードが横行し、多くの人がセキュリティリスクに晒された

どのように実現している?
認証基盤(idp)が認証を一手に引き受け、その認証結果を各サービス(sp)に返す、という仕組みで解決した。

具体的には以下のプロトコルを用いて解決している

  • saml
  • oidc

アナロジー:「テーマパークのリストバンド」方式

  • ユーザー:来場者
  • IdP:入場ゲート
  • SP:パーク内のアトラクション、レストラン、イベントブース

  1. あなた(ユーザー)は、広大なテーマパークにやって来る。
  2. 最初にメインゲート(IdP)で、チケットと身分証を見せて本人確認される。
  3. 確認が完了すると、リストバンド(トークン)が渡される。これはあなたが「正しく認証された」ことを証明するもの。
  4. その後、パーク内の各アトラクションや施設(SP)では、リストバンドを見せるだけで入場できる。
  5. 各アトラクションはあなたの身元を個別に確認したり、毎回チケットを出させたりしない。
  6. このリストバンドは一定時間有効で、有効期限が切れれば再度ゲートで更新が必要。
  7. リストバンドには偽造防止の印(署名)がついており、各施設はそれを見て本物かどうかを即時に判断できる。
ふじしろふじしろ

Basic Authentication

ユーザ名とパスワードの組み合わせをbase64でエンコードしてリクエストと一緒に送信する認証方式。

なぜ生まれたか?何の役に立っているのか?元々認証の仕組みがなかった?
当時1995年頃(http1.0のrfc1945の発表が1996年)、特定の人にだけアクセスを許可したいというニーズが生まれた。
その課題を解決するために生まれた。
参考
https://www.tohoho-web.com/ex/http.html?utm_source=perplexity#version

当時はまだCookieもSessionも生まれていないので、リクエストの度にユーザ名とパスワードをリクエストに載せていた。

なぜエンコードするの?暗号化してないなら平文でも一緒じゃない?
エンコードの目的は、セキュリティではなく、ヘッダに載せられる情報がASCIIテキストに限られていたため。
base64エンコードすることで、様々な文字列をヘッダに乗る形式に変換している。

Basic認証が解決できなかった課題は?
セキュリティリスクの高さ・通信安全性の欠如
→暗号化されていない

Session管理機能の不足
完全にステートレスなので、ログイン・ログアウトのような概念がなく、継続性がない。

https://chatgpt.com/share/67e6b709-0710-8000-9896-0a6feb7a5e95
https://chatgpt.com/share/67e6b6ac-fe2c-8000-9797-7dc7ab175046
https://chatgpt.com/share/67eab3c7-db50-8000-9ffa-b9b0a02a9f23

以下は画像に記載されていた内容の和訳です:


認証戦略 — Basic認証

HTTPを介してリソースへのアクセスを認証する仕組み
認証情報はリクエストヘッダーに送られる

Authorization: Basic aGl0Om92ZXJhY2hpZ2c=

→ Base64エンコードされた「ユーザー名:パスワード」


どう動作するのか?

Step 1

クライアントが保護されたURLにアクセスしようとする

Step 2

サーバーがリクエストにAuthorizationヘッダーが含まれていて、有効なユーザー名とパスワードかを確認

資格情報が存在しない or 無効な場合 → 401 Unauthorized

有効な場合 → 200 OK(リソースが提供される)


HTTP/1.1 401 Unauthorized
Date: Sat, 16 May 2020 16:50:53 GMT
WWW-Authenticate: Basic realm="MyApp"

→ クライアントへの応答


realm(保護領域): 同じ認証情報を使う一連のページ。ブラウザはこの領域の情報をキャッシュし、将来再利用できる

フリーフォームのテキスト。何でも設定可能。サーバーが定義・認証を担当する


Step 3

ブラウザがwww-authenticateヘッダーに気づき、認証ダイアログを表示(右上の例のようなもの)


Step 4

ユーザーが認証情報を入力 → ブラウザがそれをBase64でエンコードし、次のリクエストにAuthorizationヘッダーとして付ける:

Authorization: Basic aGl0Om92ZXJhY2hpZ2c=

(これは base64("username:password") の形式)


Step 5

再びStep 2に戻り、サーバーが認証し、認証サイクルが続く


補足

Basic認証はAPIでも使えるが、その場合は通常のトークンベース認証と同じ扱いになる

注意: Basic認証はTLS/HTTPSがない限り安全ではない
 → 誰でも傍受・デコードできる可能性があるため


サーバーからWWW-Authenticateヘッダがレスポンスされた場合、ブラウザは以下のように対応します:

  1. サーバーが401(Unauthorized)ステータスコードと共にWWW-Authenticateヘッダを送信すると、ブラウザは自動的に認証ダイアログを表示します。

  2. このダイアログは、ヘッダに指定された認証方式に基づいて表示されます。一般的な認証方式は:

    • Basic認証:ユーザー名とパスワードの入力フォームが表示されます
    • Digest認証:より安全な方式でユーザー名とパスワードを要求します
    • NTLM/Negotiate:Windowsの認証情報を使用します
  3. ユーザーが認証情報を入力すると、ブラウザは次のリクエストにAuthorizationヘッダを追加して送信します。

  4. Basic認証の場合、ブラウザは「ユーザー名:パスワード」の形式をBase64エンコードしてAuthorization: Basic [エンコードされた文字列]という形でヘッダに含めます。

  5. 認証が成功するまで、またはユーザーがキャンセルするまで、このプロセスが繰り返されます。

  6. ユーザーが認証ダイアログをキャンセルした場合、ブラウザは401エラーページを表示します。

  7. 一度認証に成功すると、ブラウザは同じドメインへの以降のリクエストに対して、セッション中は自動的に認証情報を送信し続けます。

この動作はブラウザの組み込み機能であり、JavaScriptからは直接制御できません。

ふじしろふじしろ

Session Based Authentication

なぜ生まれた?どんな課題を解決した?
httpは設計上ステートレスで、ユーザを記憶することができない。
ステートレスということは、ログイン状態管理やショッピングカートの中身の保持が出来ないということ。

ステートフルである理由は?

メモ
ステートレスとステートフルの違いについて、「発行された認証セッションを破棄できるかどうか」で区別しているのは面白い


認証戦略 — セッションベース認証とは?

ユーザーには一意の識別子(セッションID)が割り当てられ、サーバー側のメモリに保存されます。クライアントはこのセッションIDをすべてのリクエストに含めてサーバーに送信し、サーバーはそれを使ってユーザーを識別します。

これは「ステートフル(状態を保持する)」認証方式です。

ステートフルとステートレスの違い

ステートフル(Stateful):
認証セッションは取り消す(無効にする)ことが可能。

ステートレス(Stateless):
一度発行された認証セッションは取り消すことができない。

セッションベース認証の仕組み

Step 1:クライアントがログインリクエストを送信

クライアント(ブラウザなど)がログインフォームにユーザー名とパスワードを入力して、サーバーに送信します。
例: https://some.url/login


Step 2:サーバーが認証情報を検証し、セッションを作成

サーバーがログイン情報を確認し、有効であれば新しいセッションを作成します。

一意のセッションID(例:ABCXY2)を生成して、ユーザーに紐づけた状態でサーバーのメモリに保存します(例:ユーザーID 1224に対応)。

このセッションIDがクライアントに返されます。

※セッションはメモリ、Redis、データベース、ファイルシステムなどに保存可能です。


Step 3:クライアントがセッションIDを保存

クライアントは受け取ったセッションIDをCookieに保存します(Cookieが有効な場合)。

Cookieが使えない場合は、LocalStorageやSessionStorageに保存されることもあります。


Step 4:リクエスト送信時にセッションIDを添付

クライアントは後続のリクエストにセッションIDを含めて送信します。
例: https://some.url/new-post(セッションID: ABCXY2)

サーバーは、受け取ったセッションIDに該当するユーザーが存在するかをメモリから確認します。

判定結果

存在する場合 → 正常なリクエストと見なされ、200 OK(成功)レスポンス。

存在しない場合(無効なセッションID) → 401 Unauthorized(認証エラー)レスポンス。


Step 5:ユーザーがログアウトした場合

セッションは破棄されます(サーバーから削除、Cookieも削除)。

同じセッションIDは再利用不可。


補足まとめ

セッションIDはユーザーを識別するための一意のトークン。

サーバーはこのIDを保持し、状態を管理する。

ステートフルなため、サーバー側のセッション破棄でログアウトを強制することも可能です。