JSON Web Token(略称:JWT)は現在最も人気のあるクロスドメイン認証ソリューションです。この記事ではその原理と使い方を紹介します。
I. クロスドメイン認証の問題
インターネットサービスはユーザー認証と切り離せません。一般的なプロセスは以下の通りです:
- ユーザーがユーザー名とパスワードをサーバーに送信します。
- サーバーが検証に成功した後、ユーザーロール、ログイン時間などの関連データを現在のセッションに保存します。
- サーバーはsession_idをユーザーに返し、ユーザーのCookieに書き込みます。
- ユーザーからのそれ以降の各要求で、session_idがCookieを通じてサーバーに送信されます。
- サーバーはsession_idを受け取った後、事前に保存したデータを検索し、それによりユーザーの身元を知ります。
このモデルの問題点は、スケーラビリティが低いことです。単一のマシンでは問題ありません。しかし、サーバークラスターやクロスドメインのサービス指向アーキテクチャの場合、セッションデータの共有が必要であり、各サーバーがセッションを読み取れるようにする必要があります。
たとえば、ウェブサイトAとウェブサイトBは同じ会社の関連サービスです。現在、ユーザーがどちらか一方のウェブサイトにログインすると、もう一方のウェブサイトにアクセスするときに自動的にログインするようにする必要があります。これをどのように実現するのでしょうか?
1つの解決策は、セッションデータを永続化し、データベースやその他の永続層に書き込むことです。各種サービスは要求を受け取った後、永続層からデータを要求します。この解決策の利点は、アーキテクチャが明確なことですが、欠点は作業量が比較的多いことです。また、永続層が故障すると、単一障害点が発生します。
もう1つの解決策は、サーバーが単にセッションデータを保存しないことです。すべてのデータはクライアントに保存され、各要求とともにサーバーに送信されます。JWTはこの解決策の代表的なものです。
II. JWTの原理
JWTの原理は、サーバーが認証した後、JSONオブジェクトを生成してユーザーに返すことです。例えば以下のように:
{"name": "Alice", "role": "admin", "expiration time": "0:00, July 1, 2024"}
その後、ユーザーがサーバーと通信するとき、このJSONオブジェクトを返送する必要があります。サーバーは完全にこのオブジェクトに基づいてユーザーの身元を判断します。ユーザーがデータを改ざんするのを防ぐため、サーバーはこのオブジェクトを生成するときに署名を追加します(詳細は後述)。
サーバーはもはやセッションデータを保存しません。つまり、サーバーはステートレスになり、拡張が容易になります。
III. JWTのデータ構造
実際のJWTはおそらく以下のようなものです:
非常に長い文字列で、ドット(.)で3つの部分に分割されています。JWTの内部には改行はありません。ここでは表示の便宜上、複数行に書いています。
JWTの3つの部分は以下の通りです:
- ヘッダー(Header)
- ペイロード(Payload)
- 署名(Signature)
1行で書くと以下のようになります:
Header.Payload.Signature
以下でこれら3つの部分を順に紹介します。
3.1 ヘッダー
ヘッダー部分はJWTのメタデータを記述するJSONオブジェクトで、通常は以下のようになります:
{"alg": "HS256", "typ": "JWT"}
上記のコードで、alg属性は署名アルゴリズム(algorithm)を表し、デフォルトはHMAC SHA256(HS256と表記)です。typ属性はこのトークンのタイプを表し、JWTトークンは一律JWTと書かれます。
最後に、上記のJSONオブジェクトはBase64URLアルゴリズムを使用して文字列に変換されます(詳細は後述)。
3.2 ペイロード
ペイロード部分も、実際に送信する必要があるデータを保存するためのJSONオブジェクトです。JWTは7つの公式フィールドを選択肢として定義しています。
- iss(issuer):発行者
- exp(expiration time):有効期限
- sub(subject):主題
- aud(audience):対象者
- nbf(Not Before):有効開始時間
- iat(Issued At):発行時刻
- jti(JWT ID):シリアルナンバー
公式フィールドに加えて、この部分で独自のフィールドを定義することもできます。以下は例です:
{"sub": "1234567890", "name": "John Doe", "admin": true}
JWTはデフォルトでは暗号化されておらず、誰でも読むことができます。したがって、この部分に機密情報を入れないでください。
このJSONオブジェクトもBase64URLアルゴリズムを使用して文字列に変換する必要があります。
3.3 署名
署名部分は、データの改ざんを防ぐための最初の2つの部分の署名です。
まず、シークレットキー(secret)を指定する必要があります。このキーはサーバーだけが知り、ユーザーに漏洩してはいけません。そして、ヘッダーで指定された署名アルゴリズム(デフォルトはHMAC SHA256)を使用して、以下の式に従って署名を生成します:
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
署名を計算した後、ヘッダー、ペイロード、署名の部分を1つの文字列に結合し、各部分の間を「ドット」(.)で区切り、その後ユーザーに返すことができます。
3.4 Base64URL
前述のとおり、ヘッダーとペイロードのシリアル化アルゴリズムはBase64URLです。このアルゴリズムは基本的にBase64アルゴリズムと似ていますが、いくつかの小さな違いがあります。
トークンとして、JWTは場合によってはURLに配置されることがあります(たとえばapi.example.com/?token = xxx)。Base64には +、/、= の3つの文字があり、これらはURLで特別な意味を持つため、置き換える必要があります。= は省略され、+ は - に置き換えられ、/ は _ に置き換えられます。これがBase64URLアルゴリズムです。
IV. JWTの使い方
サーバーから返されたJWTを受け取った後、クライアントはそれをCookieまたはlocalStorageに保存できます。
その後、クライアントがサーバーと通信するたびに、このJWTを持ち込む必要があります。Cookieに入れて自動的に送信することもできますが、これはクロスドメインではできません。したがって、より良い方法は、HTTP要求ヘッダーのAuthorizationフィールドに入れることです。
Authorization: Bearer <token>
もう1つの方法は、クロスドメインの場合、JWTをPOST要求のデータ本体に配置することです。
V. JWTのいくつかの特徴
(1) JWTはデフォルトでは暗号化されていませんが、暗号化することができます。元のトークンを生成した後、シークレットキーで再度暗号化することができます。
(2) JWTが暗号化されていない場合、機密データをJWTに書き込むことはできません。
(3) JWTは認証だけでなく、情報交換にも使用できます。JWTを有効に使用することで、サーバーがデータベースをクエリする回数を減らすことができます。
(4) JWTの最大の欠点は、サーバーがセッション状態を保存しないため、使用中に特定のトークンを取り消したり、トークンの権限を変更したりすることができないことです。つまり、JWTが発行されると、有効期限まで有効であり、サーバーが追加のロジックを展開しない限り、有効期限が切れるまで有効です。
(5) JWT自体には認証情報が含まれています。漏洩すると、誰でもトークンのすべての権限を取得できます。盗難を減らすため、JWTの有効期限を比較的短く設定する必要があります。一部の重要な権限については、ユーザーがそれらを使用するときに再認証を行う必要があります。
(6) 盗難を減らすため、JWTはHTTPプロトコルを使用して平文で送信しないでください。代わりに、HTTPSプロトコルを使用して送信する必要があります。
Leapcell: The Best Serverless Platform for Web Hosting
最後に、ウェブサービスを展開するための最高のプラットフォーム:Leapcellをおすすめします。
1. 多言語対応
- JavaScript、Python、Go、またはRustで開発できます。
2. 無制限のプロジェクトを無料で展開
- 使用量に応じてのみ支払います — 要求がなければ料金はかかりません。
3. 圧倒的なコスト効率
- 使い捨て型で、アイドル料金はありません。
- 例:25ドルで平均応答時間60msで694万回の要求をサポートできます。
4. ストリームライン化された開発者体験
- 直感的なUIによる簡単なセットアップ。
- 完全自動化されたCI/CDパイプラインとGitOps統合。
- アクション可能なインサイトを得るためのリアルタイムメトリックとロギング。
5. 簡単なスケーラビリティと高パフォーマンス
- 高い同時接続数を簡単に処理するための自動スケーリング。
- オペレーションオーバーヘッドはゼロ — 構築に集中できます。
Leapcell Twitter: https://x.com/LeapcellHQ