🚪

ログインの仕組みと認証、認可の理解

2024/02/24に公開

今回はログインの仕組みや認証と認可の違いなどについて書いていきたいと思います。

ログインの仕組み

普段何気なく使っているログイン機能ですが、そもそもログインとは何なのでしょうか。

ログインとはアプリケーションなどが、ユーザーから送信された値とデータベースの情報を照合して本人確認を行う仕組みです。一般的にはユーザー登録を行う際にユーザーID・メールアドレスなどとパスワードの組み合わせがデータベースに保存され、ユーザーがログイン画面でそれを入力することでアプリケーションはログインしようとしているユーザーが誰なのかを判定し、判定に成功すればログインを許可するという流れをとっています。このログインしようとしているユーザーが誰なのかを判断する本人確認のプロセスのことを認証といいます。

認証と認可

本人確認のプロセスのことを認証というと書きましたが、認証とセットで使われる考え方に認可というものがあります。認証が本人確認であったのに対し、認可はユーザーに何かしらの権限を与えることを言います。「何かをできるようにする」というとイメージしやすいかもしれません。ただ、アプリケーション上では認証と認可が明確に区別されて画面などに表示される訳ではなく、どちらの権限もログイン時に同時に付与されることが多いので違いがイメージしにくく、混同してしまいがちです。しかし認証と認可はきちんと区別して扱うべきです。例えば有料コンテンツのあるサービスを思い浮かべてみてください。

無料でアカウント作成が可能なサービスで、ログインは誰でも可能で、有料コンテンツは課金しないと見れないようなサービスの場合、有料コンテンツが閲覧できるということは認可されているということになります。逆に有料コンテンツは見れないけれどログインはしている状態は、認証は受けているが有料コンテンツ閲覧の認可は受けていない状態になります。このように認証と認可は似ているものですが、アプリケーション開発においてセキュリティ等について考える際には違いを理解しておく必要があるので混同しないように注意しましょう。

Cookieとセッション

一般的なアプリケーションは一度ログインしたらしばらくはログインしたままの状態が維持され、その状態で様々な処理を行うことができると思います。しかし、本来であれば通信に利用しているHTTP通信はステートレス(状態が維持されない)なためログインした後もう一度アプリケーションにアクセスするとログイン状態は維持されないことになります。それでは不便なのでアプリケーションにはユーザーの状態を保持できるような仕組みが備わっています。そのためによく使われるのがCookieとセッションです。

Cookieはサーバーが発行し、ユーザーのブラウザが受け取って保持する小さなテキストデータです。主にユーザーのログイン情報や以前に行った選択を記憶し、ユーザーが再訪問したときにスムーズにアプリケーションを利用できるようにする場合に使用されます。Cookieには具体的なユーザー情報などが保存される訳ではなく、照合用のIDのようなものが与えられ、具体的な情報はサーバー側に保存されます。その理由はCookieはユーザーが参照、変更できてしまうこともあり、秘密情報を保持するのには向かないからです。Cookieに保存されるID自体も推測を難しくするために十分に長い桁数の乱数が利用されます。Cookieと照合される、サーバー側で保持する値をセッションと言います。

セッション

セッションはサーバー側でユーザー固有の情報を保持するためのものです。先ほどCookieの説明のときに書いた照合用のIDはセッションIDと呼びます。セッションIDがサーバー側でも保持されており、それとユーザーからのリクエストと一緒に送られてくるセッションIDが一致すれば、セッションIDに対応する情報を用いてユーザー固有の情報をレスポンスとして返してくれるのです。Cookieとセッションを用いたログインとその状態の保持の関係を図に表すと以下のようになります。

Cookieとセッションの違い

Cookieとセッションはセットで使われることもあり似たようなものではありますが、それぞれ違いや特徴があります。それぞれの違いは以下のようなものがあげれられます。

セキュリティ面

  • Cookie
    Cookieはブラウザに保存されるため外部からの攻撃を受けやすいです。そのため機密情報を保存するのには向きません。HTTPSを使用した安全な通信を利用することや、HttpOnlyフラグを設定する(JavaScriptを悪用してCookieを盗み出すクロスサイト・スクリプティング攻撃のリスクを軽減するため)などして適切に対処する必要があります。

  • セッション
    セッションはサーバー側で保存されるためセキュリティリスクは比較的小さいです。そのためユーザー固有の情報などはセッション側に保存されます。ただセキュリティリスクが全くない訳ではなく、Cookie情報が漏洩し、セッションIDが第三者に知られることやセッションIDを推測されてしまうリスクはあります。そのため、セッションIDを更新する仕組みや複雑なセッションIDを作成できる仕組みを利用するなどして対策をとる必要があります。

データの保存量

  • Cookie
    Cookieにはサイズ制限があり、一般的には1つのドメインあたり4KBまでです。

  • セッション
    セッションはサーバー側で管理されるため基本的に容量に制限はありません。ただ、サーバーのリソースを消費して保存することになるので定期的に不要なデータは削除するなどリソース管理を行う必要があります。

有効期限

  • Cookie
    Cookieには有効期限が設定可能で、期限が切れると自動的に削除されます。有効期限が設定されていない場合はブラウザが閉じられると削除されますが、多くのWebブラウザはセッション復元機能を持っているため、再起動時にセッションが復元され、同時にCookieも復元されることがあります。

  • セッション
    セッションにも有効期限が設定可能で基本的に無活動の期間に対して設定します。そのため、一定時間アクティブな動作がなければ期限切れになります。また、ブラウザを閉じた場合にも終了します。

セッションの保存先

セッションはサーバー側に保存されるということですが、具体的にサーバーのどこに保存されるのでしょうか。セッションは主に4つの場所に保存されることがあります。

1,メモリ内のストレージ
多くのウェブアプリケーションでは、デフォルトでセッションデータはサーバーのメモリ内に保存されます。これは実装が簡単で、かつ高速にアクセスできるため、データ量が多くない場合には適しています。しかし、サーバーの再起動時にデータが失われるため、永続性が必要な場合や大規模なアプリケーションには不向きです。また、サーバーのスケールアウトを行う場合、セッションの共有や同期が問題になることがあります。

2,ファイル
サーバーのファイルシステムもセッションの保存先の候補の一つです。これは、メモリへの保存に比べてデータの永続性を確保できる方法ですが、メモリを使用する場合と同様に、サーバーのスケールアウトを行う際にはセッションデータの共有や同期が課題となります。

3,データベース
セッションデータをデータベースに保存する方法もあります。データベースにセッションを保存することで、複数のサーバー間でセッション情報を共有しやすくなるためサーバーのスケーラビリティとセッションの永続性を両立できます。ただし、データベースへのアクセスはメモリへのアクセスに比べて遅くなる可能性があるため、パフォーマンスに影響を与えることがあります。

4,セッションストア
Redisのような専用のセッションストアを使用する方法もあります。これらのストアは、高速なデータアクセスとスケーラビリティを提供するように最適化されています。複数のサーバー間でセッションデータを共有する場合に特に有効で、大規模なウェブアプリケーションに適しています。

セッションの保存先はアプリケーションの要件やスケーラビリティ、パフォーマンスやデータの永続性などを考慮して選択されます。近年はスケーラビリティの考慮に加えてマイクロサービス化によりサーバーサイドが細分化されたアーキテクチャが増えたことなどもあり、セッションストアが使用されることが多くなっています。

ここまでCookieとセッションを用いたログインの仕組みについて書いてきましたが、それ以外にもトークンを使ったログインプロセス管理の方法も存在します。

トークン

Webにおけるトークンとはユーザー情報などのサーバーが必要とする情報を保持する文字列のことです。今回はソフトウェア開発において使用されることの多いJWTというトークンを中心に解説していきます。

JWT

JWTとはJSON Web Tokenの略でユーザー情報などをJSON形式で保持して、内容の改ざんを検知することができるトークンです。
https://jwt.io/introduction

JWTの詳細についてはこちらのサイトに分かりやすくまとまっています。
https://scgajge12.hatenablog.com/entry/jwt_security

JWTを使ったログインプロセスは以下のような流れになっています。

1,ログイン
ユーザーはユーザー名・ユーザーIDなどとパスワードをサーバーに送信します。

2,サーバーによる認証
サーバーは提供された認証情報を検証します。

3,JWTの生成と送信
認証に成功すると、サーバーはユーザーの情報からJWTを生成し、ユーザーに送り返します。

4,クライアントがJWTを保存
ユーザーは、受け取ったJWTを保存します(例: ブラウザのローカルストレージ、セッションストレージ、Cookieなど)。

5,リクエスト時にJWTを送信
その後、クライアントは検証が必要なリクエストをサーバーに送る際、HTTPヘッダーにJWTを含めて送信します。

6,サーバーがJWTを検証
サーバーは受け取ったJWTの署名を検証し、有効であればリクエストを処理します。

トークンを用いたログインとCookieとセッションを用いたログインの大きな違いは、サーバー側にデータを保持するかどうかです。トークンの場合はセッションのようなデータ保持の仕組みが必要ありません。必要な情報はトークンの中に含まれているので、トークンだけで自己完結できるのです。

また、Cookieとセッションが認証を維持するための機能であるのに対し、JWTを使ったログインプロセスでは最初にユーザー認証を行なったあとはJWTは認可のプロセスに利用されます。JWTの中にはユーザーに関する情報もエンコードされた状態で含まれてはいるのですが、あくまでサーバーがJWTを用いて確認するのはJWTの中のユーザー固有の情報ではなく、そのJWTがどのような権限を持っているかということです。

WebAPIとトークン

トークンを使った認可のプロセスはWebAPIなどにも利用されています。ユーザーがX(旧Twitter)に投稿する機能を持ったアプリケーションについて考えてみます。Zennにもあるような記事をXで共有できるような機能がイメージしやすいかと思います。この機能を利用する流れは以下のようになります。

1,アプリケーションの登録
まず、アプリケーションがXのAPIを利用するためには、アプリケーション側でAPIキーとAPIシークレットキーを取得する必要があります。このAPIキーとAPIシークレットキーはユーザーがアプリケーションを通して、別のサービス(今回の例でいうX)上の自分の情報にアクセスすることを許可する際に利用されます。今回はこの部分の詳細は割愛します。

2,ユーザー認証と認可のリクエスト
ユーザーがアプリケーションとの連携機能を使用しようとすると、アプリケーションはXのAPIにユーザーがXで認証を行うためのリクエストトークンの発行を要求します。リクエストトークンが発行されると、ユーザーの画面がXの認証ページにリダイレクトされます。このリダイレクトの際にXの認証画面にリクエストトークンが一緒に渡るようになっているので、どのアプリケーションを利用しているユーザーからのリクエストであるかが識別できるようになっています。ユーザーは認証画面で、アプリケーションがユーザーのXアカウントへのアクセスを要求していることを確認し、問題なければXのログインフォームにログイン情報を入力し、アプリケーションのXアカウントへのアクセスを許可します。ユーザーがアクセスを許可すると、Xはアプリケーションに対してリクエストトークンと交換する形でアクセストークンを発行します。

3,アクセストークンの使用
アプリケーションは、このアクセストークンを使用して、XのAPIを介してユーザーのXアカウントにアクセスできるようになります。具体的には、ツイートを投稿するAPIエンドポイントにリクエストを送信する際に、このトークンを使用します。アクセストークンは、ユーザーがアプリケーションに与えた権限(この場合はツイートを投稿する権限)内でのみ、XのAPIにアクセスするために使用されます。

4,ツイートの投稿
アプリケーションは、ユーザーから入力されたツイートの内容とともに、アクセストークンをHTTPヘッダーに含めたAPIリクエストをXに送信します。XのAPIはリクエストを検証し、内容が正しければユーザーのアカウントからツイートを投稿します。

一連の流れを図に表すと以下のようになります。

このように、トークンはユーザーやアプリケーションに特定の処理を行う権限(認可)を与えるために利用されているのです。

最後に

今回はログインの仕組みや認証、認可について簡単に書いてみました。基本的なことですが、どこでも使う知識なのでしっかり間違いなく身につけておきたいです。最後までご覧いただきありがとうございました。

Discussion