セッションベース認証とトークンベース認証の違いを分かりやすくまとめてみる
Web アプリケーションにおける認証方法は複数存在しますが、その中でもよく用いられるのがセッションベース認証とトークンベース認証です。
今回はこれらの違いについて説明したいと思います。
セッションベース認証
セッションベース認証では、下図のようにして認証を行います。
具体的な流れを次に示します。
- ユーザーの認証を経て、サーバーでセッション ID を発行します。このときサーバーではセッション ID とユーザー情報を対応づけておきます。
- サーバーはブラウザにセッション ID を返します。
- ブラウザは Cookie にセッション ID を保存します。
- ブラウザは保存しておいたセッション ID を含めた形でサーバーにリクエストを送ります。
- サーバーはリクエストに含まれるセッション ID を確認し、対応するユーザー情報を取得します
- サーバーはそのユーザーがアクセス可能なリソース (サーバー側の実装でどのユーザーがどのリソースにアクセス可能かを決めておきます) を返します。
ログアウトした場合は、ブラウザでセッション ID を別の値に更新しつつ、サーバーでもセッション ID とユーザー情報の対応を破棄します。
これで元々のセッション ID を用いてユーザー情報やリソースにアクセスすることはできなくなるわけです。
トークンベース認証
一方、トークンベース認証は、下図のようにして認証を行います。
具体的な流れを次に示します。
- ユーザーの認証・認可を経て、サーバーでアクセストークンを発行します (セッションベース認証と異なり、アクセストークンとユーザー情報は対応づけられません)。アクセストークンには、有効期限やそのトークンでアクセス可能なリソースの範囲 (スコープと呼ばれる) などの情報が含まれています。またアクセストークンは基本的に改ざんが困難な JWT 形式になっています。
- サーバーはブラウザにアクセストークンを返します。
- ブラウザは Cookie などにアクセストークンを保存します。
- ブラウザは保存しておいたアクセストークンを含めた形でサーバーにリクエストを送ります。
- サーバーはリクエストに含まれるアクセストークンを検証し、改ざんがされておらず有効期限などにも問題がないことを確認します。
- サーバーはそのトークンでアクセス可能なリソース (サーバー側でどの “スコープ” がどのリソースにアクセス可能かを決めておきます。どの “アクセストークン” がどのリソースにアクセス可能か、ではない点にご留意ください) を返します。 [1]
セッションベース認証とトークンベース認証の違い
ステートフルなセッションベース認証、ステートレスなトークンベース認証
両者の最も大きな違いは、セッションベース認証がサーバーに認証のための情報 (セッション ID とユーザー情報の対応) を持たせておくのに対し、トークンベース認証はサーバーにそうした情報を持たせずトークンの検証のみによって認証を行う点です。
これはつまりセッションベース認証はステートフルであり、トークンベース認証はステートレスであるということです。
セッションベース認証がステートフルな通信を実現できるというメリットを持つ一方で、トークンベース認証は (サーバーに認証のための情報を持つ必要がないため) ユーザーが増加した時のサーバー負荷がセッションベース認証よりも少なく、よりスケーラブルなシステムを実現できるというメリットを持ちます。
セッション ID を無効化できるセッションベース認証、アクセストークンを無効化できないトークンベース認証
これはトークンベース認証の最大のデメリットですが、基本的にアクセストークンは無効化できません。
この意味を理解するために、トークンベース認証におけるログアウトを考えてみましょう。
トークンベース認証でログアウトしたとき、サーバーは認証のための情報を持っていないため、単純にブラウザに保存していたアクセストークンを破棄します。
しかし前述のとおり、トークンベース認証はトークンの検証のみによって認証を行うため、ブラウザで破棄されたとてアクセストークンそのものは依然有効なわけです。
そのため、もしもそのアクセストークンが悪意あるユーザーの手に渡っていた場合、正規のユーザーがログアウトした後でも、悪意あるユーザーはリソースにアクセスできてしまうのです。
一方セッションベース認証であれば前述の通り、ログアウト後に元々のセッション ID を用いてユーザー情報やリソースにアクセスすることはできません。
アクセストークンの流出リスクへの緩和策
一応、アクセストークンの流出リスクへの緩和策が存在するので、代表的なものを紹介しておきます (緩和策であり完全な解決策ではない点にご留意ください)。
1 つ目が、アクセストークンの有効期限を短く設定することです。有効期限を短くすることでトークンが流出したときの被害を最小限に抑えようというシンプルな発想です。
ただ単純にトークンの有効期限を短くするだけではユーザーに求める認証回数が増えユーザービリティが損なわれてしまうため、アクセストークンを新しいものに取り替える機能をもつトークン (= リフレッシュトークンと呼ばれており、アクセストークンよりも有効期限が長く設定されています) を活用して、セキュリティとユーザビリティのバランスを取ることが多いです。
2 つ目が、サーバーにアクセストークンのブラックリストを持たせておく方法です。
流出の恐れがあるアクセストークンをブラックリストに登録しておき、トークンを検証するタイミングでブラックリストの確認も行うようにします。
ただしトークンの検証のみで認証ができるというトークンベース認証の利点が損なわれ、スケーラビリティが低くなってしまうというデメリットがあります。
セッションベース認証とトークンベース認証のユースケース
通常の Web アプリケーションではセッションベース認証を用いることが多いです。
一方、API ではトークンベース認証を用いることが多いように思います。特に Stripe API や Gmail API など、不特定多数のクライアントを認証する必要がある API では、スケーラビリティの観点からトークンベース認証が使われることが多いです。
セッションベース認証とトークンベース認証を併用するパターン
あまり一般的ではないと思いますが、セッションベース認証とトークンベース認証の併用するパターンもあり得ると思います。
例えば下図のように、特定の SPA のために作成された API があり、トークンベース認証を行う認可サーバーを別で立てているようなケースでは、二つの認証方法を併用するケースがあり得ます。
このような構成の場合、SPA は認可サーバーで発行されたアクセストークンを用いて API にリクエストを送ることになりますが、今回の API は不特定多数のクライアントを認証する必要はなく、ステートレスである必要性もさほど高くありません。
また前述の通り、セッションベース認証には、ステートフルな通信ができる、セッション ID が流出した場合でも無効化ができるというメリットがあります。
こうしたケースでは二つの認証方法を併用し、セッションベース認証を行った上で、トークンベース認証を行います。
こうしておけばログアウトによってセッション ID を無効化してしまえば、例えアクセストークンが有効であっても、セッションベース認証の時点ではじくことができるというわけです。
まとめ
今回は Web アプリケーションにおける認証方法の中でも特に重要な「セッションベース認証」と「トークンベース認証」についてまとめてみました。
この記事が少しでも理解の助けになれば幸いです。
内容に間違いがあれば、コメントでご指摘いただけると嬉しいです。
いいね、フォローもぜひお願いします 🐳🐣🐙
-
これは個人的な考えですが、この仕組みからするに、トークンベース認証で実際に行っているのは「トークンの認証 (検証)」であって「ユーザーの認証」ではないのかなと思っています。
なので個人的には「トークンベース “認可” (トークンの権限を認めてリソースへのアクセスを許可する)」といった方がしっくりくるのですが、一般的には「トークンベース “認証”」という言葉が広く使われています。
その理由を考えるに、1 つ目は実際の運用では (その是非はさておき) トークンにユーザー ID を含めておきサーバー側でそのユーザー ID を元にユーザー情報を取得するような使い方をすることがままあるため、2 つ目は言葉の使い方として一般に、許可証を発行する行為を認可、発行した許可証を検証する行為を認証ということがあるためかなと思っています。
なお一方で、セッションベース認証では途中でセッション ID がユーザー情報に紐付くため「ユーザーの認証」を行っていると言えると思っています。 ↩︎
Discussion