JSON Web Token(ジェイソン・ウェブ・トークン)は、JSONデータに署名や暗号化を施す方法を定めたオープン標準 (RFC 7519) である。略称はJWT。

## 概要

JWTでは、トークン内に任意の情報(クレーム)を保持することが可能であり、例えばサーバはクライアントに対して「管理者としてログイン済」という情報を含んだトークンを生成することができる。クライアントはそのトークンを、自身が管理者としてログイン済であることの証明に使用することができる。トークンは当事者の一方(通常はサーバ)または両方(もう一方は公開鍵を提供する)の秘密鍵により署名されており、発行されたトークンが正規のものか確認することができる。

JWTのトークンはコンパクトな設計となっており、またURLセーフであり、特にウェブブラウザでシングルサインオン (SSO) を行う場合に使いやすくなっている。トークンには一般的に認証プロバイダやサービスプロバイダが認証したユーザー識別情報が格納される他、各々のサービスで必要な情報も格納される。

JWTは他のJSONベースのオープン標準であるJSON Web Signature (JWS, RFC 7515) とJSON Web Encryption (JWE, RFC 7516) に拠って立っている。

## 構造

JWTのトークンは以下の3つの要素から構成される。

|  |  |  |
| --- | --- | --- |
| ヘッダー | ``` {  "alg" : "HS256",  "typ" : "JWT" } ``` | 署名生成に使用したアルゴリズムを格納する。 左記の`HS256`は、このトークンがHMAC-SHA256で署名されていることを示す。  署名アルゴリズムとしては、SHA-256を使用したHMAC (HS256) や、SHA-256を使用したRSA署名 (RS256) がよく用いられる。JSON Web Algorithms (JWA, RFC 7518) では認証や暗号化用のさらに多くのアルゴリズムが提示されている。 |
| ペイロード | ``` {  "loggedInAs" : "admin",  "iat" : 1422779638 } ``` | 認証情報などのクレームを格納する。JWTの仕様では、トークンに一般的に含まれる7つの標準フィールドが定義されている。また用途に応じた独自のカスタムフィールドを含むこともできる。 左記の例では、トークン発行日時を示す標準のクレーム (`iat`) と、カスタムクレーム (`loggedInAs`) を格納している。 |
| 署名 | ``` HMAC-SHA256(  base64urlEncoding(header) + '.' +  base64urlEncoding(payload),  secret ) ``` | トークン検証用の署名。署名は、ヘッダーとペイロードをBase64urlエンコーディングしてピリオドで結合したものから生成する。署名はヘッダーで指定された暗号化アルゴリズムにより生成される。左記はHMAC-SHA256形式でのコード例である。Base64url方式は、Base64を元に特殊記号やパディングの扱いを変えたものである。 |

これら3つの要素は、Base64urlエンコーディングされた上で、ピリオドにより結合される。以下にコード例を示す。

上記データは、秘密鍵が"secretkey"の場合、以下のようなトークンとなる。

このように生成されたトークンは、HTMLとHTTPの仕組みの中で簡単に取り扱うことができる。

## 使用

ユーザーがサーバにログインを行う場合、従来のセッションによる認証ではCookieにてセッションIDが返されるが、JWTにおいてはトークンが返され、それをローカルに保存して利用する(主にlocal storageやsession storageが用いられる。セッションIDのようにCookieを用いる場合もある)。

ユーザーが認証が必要な機能やリソースにアクセスする際、クライアントはトークンを何らかの手段、主として`Authorization`ヘッダーで`Bearer`スキーマを用いてサーバに送信する。この場合、`Authorization`ヘッダーは以下のような形式となる。

JWTは、サーバ上に認証状態を保持しないステートレスな認証方式である。サーバは`Authorization`ヘッダーで渡されたトークンが正しいかだけを検証し、アクセスを許可する。JWTにおいては、認証に必要な情報は全てトークン内に格納されており、データベースへの問い合わせを削減することができる。

## 標準フィールド

RFCにおいては、ペイロードに含める以下のような標準フィールド(クレーム)が定義されている。

| コード | 名称 | 説明 |
| --- | --- | --- |
| `iss` | Issuer | トークン発行者の識別子。 |
| `sub` | Subject | トークンの主題の識別子。 |
| `aud` | Audience | トークンが意図している受信者の識別子。トークンを受け付ける受信者は、この値に自身が含まれるかを識別しなければならない。もし`aud`クレームが存在し、かつ自身が含まれない場合、トークンを拒否しなければならない。 |
| `exp` | Expiration Time | トークンの有効期限。この期限以降の場合、トークンを受け付けてはならない。有効期限は1970-01-01 00:00:00Zからの秒数を数値で指定する(UNIX時間)。 |
| `nbf` | Not Before | トークンの開始日時。この期限以降の場合、トークンを受け付けてよい。秒数を数値で指定する。 |
| `iat` | Issued at | トークンの発行日時。秒数を数値で指定する。 |
| `jti` | JWT ID | 発行者ごとトークンごとに一意な識別子。 |

また、ヘッダーには以下のフィールドが使用可能である。

| コード | 名称 | 説明 |
| --- | --- | --- |
| `typ` | Token type | トークンの形式。`JWT`とすることが推奨される。 |
| `cty` | Content type | JWTを入れ子にして署名や暗号化を行う場合、このフィールドに`JWT`を指定する。それ以外では通常指定しない。 |
| `alg` | Message authentication code algorithm | 発行者が使用した署名アルゴリズム。任意のアルゴリズムが指定可能だが、いくつかのアルゴリズムは安全ではない。 |
| その他、JWSとJWE由来のヘッダーが存在する。 | | |

## 脆弱性と批判

JWTはステートレスであることから、JWT単体ではトークンを無効にすることが出来ない。従来のセッション同様、サーバに状態を保持すれば可能だが、その場合ステートレスの利点は失われる。

セキュリティコンサルタントのTim McLeanは、複数のJWTライブラリが`alg`クレームに署名無し (`none`) 等を指定した不正なトークンを処理してしまう脆弱性を報告した。これらの脆弱性は修正されたが、McLeanは同様の問題を防ぐため`alg`クレーム自体を廃止すべきだと主張している。

署名アルゴリズムの脆弱性については、以下のような方法で対策が可能である。

1. JWTヘッダーだけを見て検証しない。
2. アルゴリズムについて知る。
3. 適切なキーサイズを用いる。