Closed6

Webにおける認証情報、JWTの取り扱いとか

takecchitakecchi

要件

  • スケールアウトが簡単である。ステートレスが望ましい
  • 一回ログインしたら後は基本永続にしたい
  • サーバー都合でログアウトさせられること。不正利用確認できたら止められる
  • 将来的にアプリでも使えるAPI

書き出してみたら意外と少ない

用語の定義

当記事では以下の用語は以下とする。

  • ステートレスな認証: 認証情報をサーバー側で管理しません。ここではJWTを使用。
  • ステートフルな認証: 認証情報をサーバー側で管理します。DBやRedisなどで管理。
  • アクセストークン: ステートレスな認証として使用されます。ここではJWTを指す。
  • リフレッシュトークン: アクセストークンを発行するためのトークン。ステートフルな認証として使用されます。DBやRedisで管理。
  • リボーク: トークンをサーバー側の都合で無効化すること
takecchitakecchi

JWTとは

  1. {"user_id":1,"有効期限":"2024-01-01"}というJSONがあります。
  2. JSONをサーバーだけが知ってるキー値(例:ABCDEF)を使ってハッシュ化(例:HOGEHOGE)します。
  3. クライアントにはJSON+ハッシュ値を渡します。(例:{"user_id":1,"有効期限":"2024-01-01"}HOGEHOGE)

これがJWTです。
サーバーサイドはJSON+ハッシュ値を受け取り、検証(JSONをハッシュ化したらHOGEHOGEになるか)することでJSONが改竄されてないことを確認できます。

つまり同じハッシュ値を持ってるだけでどのサーバーでも検証が出来るってことです。

要件を満たす

スケールアウトが簡単である。ステートレスが望ましい

アクセストークン(JWT等)を使用することで実現が可能。
ただし仕組み上サーバーサイドでリボークが出来ない為、有効期限は短く設定しておくこと。
(厳密にはリボークできるが、サーバーのキー値を変える為影響が大きい)

一回ログインしたら後は基本永続にしたい

リフレッシュトークンの期限を無限(または長期間)とすることで対応。

サーバー都合でログアウトさせられること。不正利用確認できたら止められる

リフレッシュトークンはステートフルな認証(DBやRedis管理)である為、データを消すことでアクセストークンの新規発行を止めることが出来ます。

アクセストークンは期間内であれば検証が通るので、有効期間内の悪用を許容する必要があります。
重要な情報に対するアクセスにはパスワードなど制限をかけるといった対策をしましょう。

将来的にアプリでも使えるAPI

ログインした際、SetCookieだけではなくレスポンスボディにリフレッシュトークンを含めてやると使いやすいかも。アプリからSetCookieの値取れると思うのでマストではない

takecchitakecchi

まとめ

アクセストークン(ステートレスな認証)について

ここで話しているアクセストークンはステートレスなものでDBやRedisで検証が行われないものを指す。
その手段として採用されているのがJWTという話。

→流出した場合キー値の変更以外で止められないので、期限は短めに設定しておく

リフレッシュトークン(ステートフルな認証)について

アクセストークンの再発行に使用するトークン。
リフレッシュトークン自体はDBやRedisに格納する為、リボークが可能。
仕組み上リフレッシュトークンについてはステートフルにするしかない。

許容するリスクと対策

アクセストークンが流出した場合、有効期限内の悪用は許容する。
リフレッシュトークンをリボークすることで、永続的な悪用はさせない。

また、パスワードの変更や決済といった大切な動作を行う場合はパスワードの入力を求めるなどで対策とする

takecchitakecchi

Webサイトにおけるトークン情報の格納先

アクセストークン: 正直どこでもいい。localStorageでもいいし、SPAならインメモリでもいい。
リフレッシュトークン: httpOnlyなCookieとして格納がベター。localStorageでもいいけど

どこでもいい&httpOnlyなCookieとしての格納がベターな理由

XSSを行われた際に直接トークン取られるか、取れないかの違いでしかない。
httpOnlyなCookieだと直接値を取られることはないが、withCredentialsを付けてPOSTすることでアクセストークンの再発行が可能なので、XSSには効果が薄い。
サイト閉じたら不正利用されなくなるので、そういった意味では後者がベターという話。

takecchitakecchi

結論

ステートフルな認証(DBやRedis)とステートレスな認証(JWT)を使いこなすことで認証のオーバーヘッドを軽減することができる。

JWTはあくまでステートレスに個人を特定&検証するための仕組みである。

このスクラップは2023/09/11にクローズされました