Web上でのユーザログイン情報保持について考える

最近社内で新規サービス立ち上げPJに関わる機会があり、その際にユーザのログイン/ログアウト状態の保持について触れる機会がありました。ただ、想像以上にこの辺りをまったく理解していなかったことに気が付いたので、自分で調べたことをまとめてみました。もし間違っているところなどあれば、コメントいただけると嬉しいです。特にステートフルとステートフルや、cookie vs web storageの比較はよく見ますが、これらをビッグピクチャーで考えたことがなかったので、全然理解していませんでした…

### ステートフルとステータス
Http通信はそもそも`ステートレス`です。これは元々ドキュメント公開の方法としてのみウェブサイトなどが使われ始めていたことによるものですが、現代ではオンラインショップやアプリなど、状態をページを跨いでやり取りしたりする際にステートが必要になり、ステートフルというものが使われだしました。

#### ・ステートフルについて
##### どう行うのか
ステートフルセッションはまず`バックエンドサイド`で作成されます。そしてこのセッション参照IDをクライアント側に送ります。クライアント側でこのセッション参照IDを保持し、サーバーサイドにあるこの参照IDを元にユーザが認証済みであるかなどを判断します。このセッションIDを無効にしたい際は、サーバーサイドでこのセッションIDを削除するだけで実現可能です。

##### メリット
* セッションをいつでも無効にすることが出来る
* 実装や、1セッションサーバーシナリオの管理が簡単
* セッションデータをその後変更可能

#### デメリット
* サーバーの管理が大変
セッション管理はRedisなどのデータベースを用意する必要があり、たくさんのログインが集中したりすると、このサーバーのスケーラビリティが問題になってきます。

#### ・ステートレスについて
##### どう行うのか
ステートレスはステートフルの問題点を解決するべく使われることが多い方法です。よく使われるのはOpenID ConnectやJWTですが、これらの方法はバックエンド側でセッションを管理するDBなどの仕組みが必要がない為、その点の面倒さを解決することは出来ます。

ステートレスの場合は、ユーザのセッション情報を`クライアントサイド(ブラウザ)`に保存します。そのためサーバーサイドではペイロードと署名がマッチするかどうかだけを見て有効性チェックを行います。

#### メリット
* サーバー管理が不要
* スケールアウトが楽

#### デメリット
* セッションをいつでも無効にできるわけではない
セッション情報がクライアント側にあるため、サーバー側でセッション削除をすることが出来ません。
* セッション情報の変更はセッションの有効期限が切れてからでないと行えない

参考:
・[Stateful and stateless authentication](https://medium.com/@kennch/stateful-and-stateless-authentication-10aa3e3d4986)

### Session vs Token認証
#### Session
Sessionは前述のステートレスの説明にもあった通り、ユーザーがログインした際にバックエンドでセッションIDを発行し、それをcookieに保存します。そしてリクエストの度にこのcookieに保存された値がサーバに送られ、サーバ側でこのセッションIDを確認します。

#### Token認証
こちらは大抵localStorageにTokenが保存されて、リクエストの度にヘッダーにこれをつけて送ります。サーバ側ではこれをチェックして、ユーザー情報を取得します。主な二つの違いはToken認証の場合ユーザーの状態はサーバで管理せず、トークンに含まれており、クライアントサイドでのみ保持されます。

:::note warn
ただ、ここで注意ですが、JWTをセッション管理に使う事例をネットではかなりよく見るものの、 推奨はされていません。
:::

なぜかというと、上のステートレス/ステートフルでも書きましたが、JWTはサーバーサイドでの管理が必要なくなる反面、セッションを無効にしたいときに自由にそれが出来ないからです。(JWTのトークンの有効期限が切れるのを待つしかない。)

これが何を引き起こすかというと、例えばログイン/ログアウトという機能があってもユーザがログアウトした際に実際はログアウトしていない、とか何らかの理由があってユーザをシステムからブロックしても実際にはブロックされていないのでシステム内に入って情報を見ることが出来てしまう。管理者から外す、ということをしても、トークンが有効な間は管理者オンリーの機能が使えてしまう、などなど。

これを防ぎつつJWTを使うには、レフレッシュトークンを発行する前提でJWTのトークンの有効期限をなるべく短く設定し、セッションが切れたらリフレッシュトークンを使う。そしてリフレッシュトークンはユーザと紐づけ管理する、というchatworkさんの事例がありました。

まあ便利な仕組みはだからと言って何にでも使えるわけではなく、使い方はよく考えないといけないですね。。

参考:
・ [WebアプリケーションでJWTをセッションに使う際の保存先は（自分なりに説明できれば）どちらでもよいと思います](https://ryozi.hatenadiary.jp/entry/2022/02/12/073014)
・[JWTでセッション管理してはいけない](https://qiita.com/hakaicode/items/1d504a728156cf54b3f8)
・[そもそもJWTに関する私の理解は完全に間違っていた！](https://koduki.hatenablog.com/entry/2019/11/03/163014)
・[JSON Web Tokens (JWT) are Dangerous for User Sessions—Here’s a Solution](https://redis.com/blog/json-web-tokens-jwt-are-dangerous-for-user-sessions/)

### Cookie
次にcookieについてです。cookieは主にセッション管理やパーソナライゼーション(ターゲティング広告とか)、追跡に使われます。
cookieのセキュリティ面ですが、データ自体はプレーンなテキストの為、漏れて困る情報をそのまま保存するのには向いていません。また、SSLを使っていない無料wifiなどを使っている場合はサーバとのやり取り時に通信から読み取られてしまう可能性もあります。

ただcookieには一押しHttpOnlyフラグを立てることである程度セキュリティレベルを上げることができます。このHttpOnlyフラグがHttpレスポンスヘッダーに含まれていた場合、cookieはクライアントサイドスクリプトにアクセスすることができません。(ブラウザがサポートしていた場合だけですが)

参考: 
・[What is the difference between localStorage, sessionStorage, session and cookies?](https://stackoverflow.com/questions/19867599/what-is-the-difference-between-localstorage-sessionstorage-session-and-cookies)
・[Everything You Need to Know About Cookies for Web Development](https://www.freecodecamp.org/news/everything-you-need-to-know-about-cookies-for-web-development/amp/)
・[牧歌的 Cookie の終焉](https://blog.jxck.io/entries/2020-02-25/end-of-idyllic-cookie.html)

とまあ、色々な目線からユーザー認証について、その方法や仕組みについてまとめてみました。
お付き合いいただき、ありがとうございました。