JWTに関して学んだ
概要
JWT の概要とその中で使われている技術に関して理解したようです。
よく認証・認可の仕組みで使われるものです。今回は中身がどの様になっているか調べました。
JWXについて詳しく述べているわけではありません。
JWTとは
詳しくはRFC 7519を参照。
JSON Web Token (JWT) is a compact, URL-safe means of representing
claims to be transferred between two parties. The claims in a JWT
are encoded as a JSON object that is used as the payload of a JSON
Web Signature (JWS) structure or as the plaintext of a JSON Web
Encryption (JWE) structure, enabling the claims to be digitally
signed or integrity protected with a Message Authentication Code
(MAC) and/or encrypted.
JSON エンコードされたデータを電子署名をつかって2者間で整合性が取れた状態でやり取りする仕組みです。
作り方を簡単に表現すると、アルゴリズムと署名したい claims と secret を用意して、ガッとすればできあがるものです。
JWT の構造
外形は、 Header
.Payload
.Signature
です。
それぞれが .
でつながっています。
それぞれの要素について見ていきます。
このサイトで簡単に JWT がどうなるか確認できるのでお試しあれ。
Header
まずは Header を用意します。
アルゴリズムをどうするかですが、利用できるものは以下です。
- HS256
- HS384
- HS512
- RS256
- RS384
- RS512
- ES256
- ES384
- ES512
- PS256
- PS384
PS256
は見たことないですが、RSASSA-PSS using SHA-256 and MGF1 with SHA-256
ということっぽいです。
今回は発行者と検証者が一緒であることを想定しているので、HMacSHA256 で行います。
{
"alg": "HS256",
"typ": "JWT"
}
これを Base64 URL Encoding すると...
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
こうなります。
Payload
この payload のことは claims という表現をしています。
Claims-based identity の claims です。
{
"loggedInAs": "admin",
"iat": 1422779638
}
これも Base64 URL Encoding すると...
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
ちなみに iat は issued_at を表していて、発行日時を表していて、有効期限の始まりを意味します。
さて、あとはこれらのデータを使って署名するだけです。
Signature
これが JWT の肝ですね。
今回は HS256 でやるので secret は HMAC_SHA256 でシュッとつくります。
secret の key は完全なランダムな文字でキー長は 32byte 以上にしするよう気をつけます。
A key of the same size as the hash output (for instance, 256 bits for
"HS256") or larger MUST be used with this algorithm. (This
requirement is based on Section 5.3.4 (Security Effect of the HMAC
Key) of NIST SP 800-117 [NIST.800-107], which states that the
effective security strength is the minimum of the security strength
of the key and two times the size of the internal hash value.)
https://tools.ietf.org/html/rfc7518#section-3.2
https://crypto.stackexchange.com/questions/34864/key-size-for-hmac-sha256
適当にキーを作ります。
openssl rand -base64 40 | fold -w 40
aMsT1GV5kH5rWzaBfybJsTYpc0NSsyec5u6CBYjL
できました。
HMAC-SHA256(
base64urlEncoding(header) + '.' +
base64urlEncoding(payload),
secret
)
それでは上の式によって作ります。
HMAC-SHA256(
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ,
aMsT1GV5kH5rWzaBfybJsTYpc0NSsyec5u6CBYjL
)
これを実行すると...。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dnZWRJbkFzIjoiYWRtaW4iLCJpYXQiOjE0MjI3Nzk2Mzh9.JQm7WDaqsDZnnvOJerRwpf9d8FFyevGK5-HZ7jAL5p0
無事出来上がりました:tada:。
おまけ
検証
さて,JWT を作るだけでなく、検証も必要になってきます。
まず、JWT を検証するにはどのアルゴリズムを使って、どの secret key を使ったかという情報が必要です。
secret key はどっかに保管されているところからよいしょともってくるだけで良いです。
アルゴリズムはどうでしょうか。そういえば、header に入れていたので取り出して使いますか...。
と header をデコードしておもむろに取り出そうとしてはいけません。なぜなら、header はいくらでも書き換え可能なので全くセキュアではないからです。
上では述べていませんが、alg: none
というアルゴリズムを指定しない方法というのがありまして(https://tools.ietf.org/html/rfc7519#section-6)、これを利用した攻撃があったようです。
https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
ざっくりというと、Header のアルゴリズムを none
にして Payload を好き勝手いじって、 signature を空にするとなんでもおくれちゃうよってやつです。
ライブラリによっては、header のアルゴリズムをまるっと信じた設計になっているものがあり問題となったようです。
つまり、検証するアプリケーション側でアルゴリズムのチェックを行っておく必要があります。
RFC8725 では none
はセキュアにやり取りできない場合は、使うべきでないということらしいです。
(その場合、そもそも JWT を使う意味が思いつきませんが...)
https://tools.ietf.org/html/rfc8725#section-2.1
とりあえずアプリケーション側でアルゴリズム自体の検証を挟むことが大事です。
claims
主体者の何者かを key:value
で表したものくらいのイメージ
claim って直訳すると主張するっていう意味らしいですが、ちょっと何言ってるわかりません。
claims は主体(subject)が何をできるかのステートメントであり、アプリケーション側で必要なデータを記述するもののようです。
Discussion