📖

【図解で解説】JWTとは?

2024/12/31に公開

JWTとは?

JWT(JSON Web Token)は、クライアントとサーバーの2者間でセキュリティ情報を共有するために使用されるものです。

クライアントからサーバーにJWTを渡すと、サーバー側でトークンの検証が行われます。
これにより、クライアントが正しいリクエストを行なっているか認証済みであるかを確認できます。

引用:What Is JWT?

JWTを使った認証の流れ

JWTなどのトークンベースの認証の流れについては、認証の流れで図解で分かりやすく説明しているので参考にしてください。

JWTの構成について

JWTは、HEADERPAYLOADVERIFY SIGNATURE3つで構成されています。
下記画像の通り、HEADER.PAYLOAD.VERYFY SIGNATUREのような表記です。
これら3つについてそれぞれ解説します。

HEADERについて

HEADERでは、アルゴリズムトークンのタイプを設定します。

上記画像のような場合について解説します。
アルゴリズムをHS256に設定しています。
トークンのタイプはJWTに設定しています。

PAYLOADについて

PAYLOADは簡単に言うとデータ部分です。

subにはユーザーに一意に識別するものを設定します。
上記画像の場合は、ユーザーIDを設定しています。

nameにはなんでもデータを入れて良いことになっていますが、
上記画像の場合は、ユーザー名を設定しています。

iatは"Issued At"の略です。
トークンが発行された日時をUnixタイムスタンプ形式で表します。
上記画像の場合は、「1970年1月1日00:00:00 UTC」からの秒数で、2022年1月17日21時17分02秒(UTC)を表します。

VERIFY SIGNATUREについて

JWTが改ざんされていないことを保証する署名部分です。

こちらの署名の検証プロセスについて解説します。

① トークンの分割
トークンをドットで分割して、各部分を取得します。

Header:    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Payload:   eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
Signature: SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

② HEADERとPAYLOADの再エンコード
JWTのHEADERとPAYLOADを再度Base64URLエンコードして結合します。

Message = base64UrlEncode(header) + "." + base64UrlEncode(payload)
Message = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ"

③ 署名を生成
サーバーが保持している**秘密鍵(secret)**を使い、同じアルゴリズム(HS256)で署名を生成します。

Signature = HMACSHA256(Message, secret)

具体的には、以下の処理を行います。
MessageをSHA-256ハッシュ関数に渡す。
その結果をHMAC(秘密鍵付きハッシュ)で暗号化する。

Secret = "your-256-bit-secret"
Signature = HMACSHA256("Message", "your-256-bit-secret")

④ 署名の比較
トークンの署名部分(SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c)と、③で生成した署名を比較します。
一致する場合: トークンは改ざんされていないと判断。
一致しない場合: トークンが改ざんされているか、秘密鍵が間違っていると判断。

署名検証が成功すると、トークンに基づいてリクエストを処理します。

メリット

① トークンのサイズが小さいのであれば、クライアントとサーバー間で非常に迅速にトークンを渡すことができます

ユーザーがアクセスできるリソース、その権限の有効期間、ログオン中にユーザーが実行できる操作を指定できます

③ セッションベースの認証ではセッションIDをサーバー側のデータベースなどで保存しておく必要があったが、トークンベースの認証であればサーバー側でトークンの情報を保存しておく必要はない

デメリット

① サイズが大きいトークンをクライアントとサーバー間で送受信すると、パフォーマンスの影響を与える可能性があります。

一度発行したトークンは、サーバーで無効化する方法が基本的にはありません
例えば、ユーザーがログアウトしたり、権限を変更した場合でも、有効期限内のトークンは有効です。
この回避策としては、トークンに短い有効期限を設定し、定期的に新しいトークンを発行します

③ トークンが盗まれた場合、そのトークンを持つ者は有効期限が切れるまで正規ユーザーとして振る舞うことができます。
この回避策としては、HTTPSを使用して通信を暗号化し、トークンの情報が読み取れないようにしておくことです。

④ クライアント側に保存したトークンがXSS攻撃によって盗まれる可能性があります。
その回避策としては、トークンをCookieのHttpOnly属性と共に保存することで、JavaScriptからトークンの情報にアクセスできないようにしておくことです

⑤ 短い有効期限のアクセストークンと、長期有効なリフレッシュトークンの組み合わせを採用すると、実装が煩雑になります。
不正を防ぐため、リフレッシュトークンをセキュアに保存・管理する必要があります。

参考資料

jwt.io
What Is JWT and Why Should You Use JWT
What Is JWT?

Discussion