今回は「JSON Web Token」についてまとめます。
概要
JSON Web Token は略して JWT (ジョット) と呼びます。
「セッション情報をサーバーサイドで保存せずクライアントサイドで保持できる(ステートレスが実現できる)」点が特徴です。 WebAPIとか作るときは便利な仕様です。
JWTの仕様(= トークンの仕様)自体はシンプルですし、使い方も簡単です。 ただ…使い方を間違えると脆弱性ができてしまうので、使い方には要注意です。
仕様
JWTはその名に「トークン」が付く通り「トークン」の構造が重要になります。 ここではそのトークン構造がどうなっているのか詳細を見ていきます。
構造
JWTに定義されるトークン構造は以下のようになっています。
token = base64UrlEncode(header) + "." + base64UrlEncode(payload) + "." + base64UrlEncode(signature)
構成要素は以下の3要素+1エンコードです。各要素をエンコードしたものを .
(ピリオド) で結合したものがトークンになります。
- ヘッダー
- ペイロード
- 署名
- Base64URLエンコード
ヘッダーには「署名アルゴリズム」、ペイロードには「保存したいデータ」、署名には「トークンが改ざんされていないか確認するための署名」を入れます。
Base64URLエンコード は Base64エンコードとやや異なります。
Base64URLエンコードは「Base64 エンコード したとき出現する URLアンセーフ な文字( +
と /
)を URLセーフな文字( -
と _
)に置き換え、パディング( =
)を入れないURLセーフなエンコード方式」になります。
ヘッダー
「署名で利用するアルゴリズム」と「このトークンが何ものか」を指定します。
{ "typ": "JWT", "alg": "ES256" }
項目 | 名称 | 説明 |
---|---|---|
typ |
Type | 任意項目。
JWT 固定で指定。 |
alg |
Algorithm | 署名に利用するアルゴリズムを指定。
指定できるアルゴリズムはRS256 , ES256 , none など。
脆弱性の観点(公開鍵暗号方式が良い)から HSxxx と none 以外がおススメ。
指定できる値の詳細は別表(algに指定できる値)参照。 |
alg
に指定できる値
algに指定できるアルゴリズムの一覧は以下の通り。 指定できる値については RSC7518 - JSON Web Algorithms (JWA) もしくは JSON Object Signing and Encryption (JOSE) に記載があります。
値 | アルゴリズム | 暗号鍵 |
---|---|---|
HS256 | HMAC using SHA-256 | 共通鍵 |
HS384 | HMAC using SHA-384 | 共通鍵 |
HS512 | HMAC using SHA-512 | 共通鍵 |
RS256 | RSASSA-PKCS1-v1_5 using SHA-256 | 秘密鍵 |
RS384 | RSASSA-PKCS1-v1_5 using SHA-384 | 秘密鍵 |
RS512 | RSASSA-PKCS1-v1_5 using SHA-512 | 秘密鍵 |
ES256 | ECDSA using P-256 and SHA-256 | 秘密鍵 |
ES384 | ECDSA using P-256 and SHA-384 | 秘密鍵 |
ES512 | ECDSA using P-256 and SHA-512 | 秘密鍵 |
PS256 | RSASSA-PSS using SHA-256 and MGF1 with SHA-256 | 秘密鍵 |
PS384 | RSASSA-PSS using SHA-256 and MGF1 with SHA-384 | 秘密鍵 |
PS512 | RSASSA-PSS using SHA-256 and MGF1 with SHA-512 | 秘密鍵 |
none | 暗号化なし | なし |
ペイロード
保存したいデータの実態部分になります。 ペイロードに指定できる項目は「クレーム」と呼ばれ、あらかじめ決められた「予約済みクレーム」と発行者が任意に指定する「プライベートクレーム」の2種類があります。
「プライベートクレーム」は「予約済みクレーム」と衝突しなければ好きなように作れるので、ここでは「予約済みクレーム」だけ紹介します。
{ "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }
項目 | 名称 | 説明 |
---|---|---|
iss |
Issuer | 任意項目。文字列かURI。 発行者の識別子。 |
sub |
Subject | 任意項目。文字列かURI。 同じIssuer内で一意になる値(リソースオーナーのユーザー識別子)。 |
aud |
Audience | 任意項目。1件の場合は単一の文字列かURI。 複数件の場合は文字列またはURIの配列。受益者の識別子(クライアントID)。 |
exp |
Expiration Time | 任意項目。NumericDate(エポック秒)。 JWTを失効させる日時。 |
nbf |
Not Before | 任意項目。NumericDate(エポック秒)。 JWTが有効になる日時。 |
iat |
Issued At | 任意項目。NumericDate(エポック秒)。 JWTの発行日時。 |
jti |
JWT ID | 任意項目。文字列。 JWTを一意に識別するための値。 再発行を防ぐためのものなので、JWTが発行されるたびに変わる。 |
署名
発行された JWT が改ざんされていないかを確認するための証明になります。 「ヘッダーをエンコードしたもの」と「ペイロードをエンコードしたもの」をもとに署名を作成します。
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), YOUR-SECRET )
使い方
通常はリクエスト/レスポンスのヘッダーに埋め込みます。 具体的には Authorization ヘッダーの Bearer スキーマ に指定して送受信します。
Authorization: Bearer <token>
注意点
JWTを使うときはセキュリティ面に注意が必要です。 ここでは特に気を付けておきたい注意点をまとめます。
-
重要な情報は保存しない
Base64URLエンコードされただけなので、盗聴されると誰でも中身が確認できてしまいます。 常時HTTPSが言われる昨今でなかなか難しい話ですが、念のため避けるのがよいでしょう。
-
algは公開鍵暗号のものしか受け付けない
alg: none
に改ざんされると誤って改ざんされたJWTを受け入れる懸念があります。 仮に何かしらの公開鍵暗号を使っていたとしてもalg: HSxxx
(共通鍵) に変更されると、「公開鍵文字列を共通鍵として利用して」署名を生成され、誤って受け入れる懸念があります。
今回は「JSON Web Token (JWT)」についてまとめました。 参考になったでしょうか? 本記事がお役に立っていると嬉しいです!!
参考記事
- RFC7519 - JSON Web Token (JWT)
- OpenID Foundation Japan - JSON Web Token (JWT)
- JSON Web Signature (JWS)
- RFC7518 - JSON Web Algorithms (JWA)
- IANA - JSON Object Signing and Encryption (JOSE)
- RFC4648 - The Base16, Base32, and Base64 Data Encodings
- Akata Works - Base64エンコードとBase64URLエンコードについて
- Qiita - JSON Web Token(JWT)って結局使っていいの?
- JOSE(JavaScriptオブジェクトへの署名と暗号化)は、絶対に避けるべき悪い標準規格である
- JWT(JSON Web Token)の「仕組み」と「注意点」
- JWTを認証用トークンに使う時に調べたこと
- JWS 実装時に作りがちな脆弱性パターン
- Wiki - JSON Web Token
- jwt
- Qiita - 【JWT】 入門
最後に… このブログに興味を持っていただけた方は、 ぜひ 「Facebookページ に いいね!」または 「Twitter の フォロー」 お願いします!!