AWS
JSON
初心者
JWT
cognito

主要な認証サービスで利用されているJWT(JSON Web Token)の概要を理解する


まえがき


  • もともと自分の理解を目的にしてまとめてみましたが、少しでもお役に立てたら嬉しいです。

  • JWTの概要について書いており、活用例などは書いてありません。

  • JWTをお聞きしたことのない方(僕もそうでした)でも、
    主要な認証サービスで使われておりいずれ遭遇すると思うので、今のうちに頭の片隅に入れておいて損はないと思っています。


JWT のサンプル

まずイメージを持っていただくために、JWTのサンプルを用意しました。


JWTのサンプル

eyJraWQiOiJZRnJwVUpsSzZqQlErTC9VcGpVbTgZFZQa3lOaWZmOgBHVnJvgWNBYjFcL3c9IiwiYWTnIjoiUlMyNTYifQ.eyJzgWIiOiI2ZjghMGFiMi03MjQwLTQyZmEtYTRlYS04ZgVkYzY0OgU2NTUiLCJhgWQiOiI2MnZsgHQzMnE2gjlwczE4ZHE3bTFsZ2w5aCIsImVtYWlsT3ZlcmlmaWVkIjp0cnVlLCJlgmVugF9pZCI6IjY3MzMwZjMTLTcTZmItMTFlOS04ZTZhLTRkNjBlMmZmNmNkMyIsInRva2VuT3VzZSI6ImlkIiwiYTV0aF90aW3lIjoTNTU3MzY2MgE5LCJpc3MiOiJogHRwczpcL3wvY29nbml0by3pZHAuYTAtbm9ygGhlYTN0LTEuYW3hem9uYTgzLmNvbVwvYTAtbm9ygGhlYTN0LTFfajRFZ0JMTmRTIiwiY29nbml0bzp3c2VybmFtZSI6IjZmN2EwYWIyLTcyNgAtNgJmYS3hNGVhLThkNWRjNjQ4NTY3NSIsImV4cCI6MTU3NzM2OTYTOSwiaWF0IjoTNTU3MzY2MgE5LCJlbWFpbCI6InRlc3RzbmFwQHRpbWVycy3pbmMuY29tIn0.GR4Uo2EjWJwgtk7jFLPRB003A_bl0TlR-OoMLLlnB9KZBT93KCgbOQrhMV_4o0oHwjBm2p3zfCy0ZAzf7gIc_VbFKhTiK43pF2Uu850pPgepnnWmkUgWrpSVcnHFUs6SKTZUZsllJGQqr_gsoiYHgjYEkTgl60Mg3LUM7J4_vErB_7spi7yltgMumGaKiuFoL338My7YJOU3-BI4NBjGR86VQn4vcaHECOPSheTGmEW5B7jeTgk0MSAN0ykAHt6Sq7ng4Tg3nLEUcpeTA3Nt3Rw8S08glq_5ZGcyoJgAlsP7gCVg3kRNN9uJ_0eimkip7R6f02gsf_Ok8pT-IW4kag


これをみてもさっぱりだと思いますが、ここからの説明を眺めていただき、概要を理解していただけると幸いです。


JWT の概要


  • JWTとは、JSON Web Token の略であり、JWT(ジョット)と呼ばれます。



  • RFC 7519で標準化された仕様であり、様々な認証サービスで利用いられています。


    • OAuth2、OpenID Connect、AWS Cognito...

    • (補足) RFC: インターネット技術の標準化などを行うIETF(Internet Engineering Task Force)が発行している、技術仕様などについての文書群




  • JWT内に任意の情報(=クレームと呼びます)を保持することができます。


    • Username, Email etc...




  • 秘密鍵/公開鍵や、共通鍵を用いた電子署名により、JSONの改ざんをチェックできるようになっています。


    • 暗号化のアルゴリズム(RS256, HS256 etc...)によって、鍵の仕組みが変わっています。

    • トークンの発行者や受け取った方が、鍵を用いて JSON が改ざんされていないこと、トークンが正しいことを検証出来ます。




JWTの利用ケース例

Untitled Diagram (2).jpg


JWTの構成概要


  • 記事の最初に書かれているJWTサンプルの再掲です。


JWTのサンプル

eyJraWQiOiJZRnJwVUpsSzZqQlErTC9VcGpVbTgZFZQa3lOaWZmOgBHVnJvgWNBYjFcL3c9IiwiYWTnIjoiUlMyNTYifQ.eyJzgWIiOiI2ZjghMGFiMi03MjQwLTQyZmEtYTRlYS04ZgVkYzY0OgU2NTUiLCJhgWQiOiI2MnZsgHQzMnE2gjlwczE4ZHE3bTFsZ2w5aCIsImVtYWlsT3ZlcmlmaWVkIjp0cnVlLCJlgmVugF9pZCI6IjY3MzMwZjMTLTcTZmItMTFlOS04ZTZhLTRkNjBlMmZmNmNkMyIsInRva2VuT3VzZSI6ImlkIiwiYTV0aF90aW3lIjoTNTU3MzY2MgE5LCJpc3MiOiJogHRwczpcL3wvY29nbml0by3pZHAuYTAtbm9ygGhlYTN0LTEuYW3hem9uYTgzLmNvbVwvYTAtbm9ygGhlYTN0LTFfajRFZ0JMTmRTIiwiY29nbml0bzp3c2VybmFtZSI6IjZmN2EwYWIyLTcyNgAtNgJmYS3hNGVhLThkNWRjNjQ4NTY3NSIsImV4cCI6MTU3NzM2OTYTOSwiaWF0IjoTNTU3MzY2MgE5LCJlbWFpbCI6InRlc3RzbmFwQHRpbWVycy3pbmMuY29tIn0.GR4Uo2EjWJwgtk7jFLPRB003A_bl0TlR-OoMLLlnB9KZBT93KCgbOQrhMV_4o0oHwjBm2p3zfCy0ZAzf7gIc_VbFKhTiK43pF2Uu850pPgepnnWmkUgWrpSVcnHFUs6SKTZUZsllJGQqr_gsoiYHgjYEkTgl60Mg3LUM7J4_vErB_7spi7yltgMumGaKiuFoL338My7YJOU3-BI4NBjGR86VQn4vcaHECOPSheTGmEW5B7jeTgk0MSAN0ykAHt6Sq7ng4Tg3nLEUcpeTA3Nt3Rw8S08glq_5ZGcyoJgAlsP7gCVg3kRNN9uJ_0eimkip7R6f02gsf_Ok8pT-IW4kag



  • JWTの中には、ピリオド(.) が2つ含まれており、それを境目にして3つの文字列に分割できます。


    • 上記のJWTを実際に分割してみると、以下のようになります。




JWTのサンプルをピリオドで分割する


eyJraWQiOiJZRnJwVUpsSzZqQlErTC9VcGpVbTgZFZQa3lOaWZmOgBHVnJvgWNBYjFcL3c9IiwiYWTnIjoiUlMyNTYifQ
.
eyJzgWIiOiI2ZjghMGFiMi03MjQwLTQyZmEtYTRlYS04ZgVkYzY0OgU2NTUiLCJhgWQiOiI2MnZsgHQzMnE2gjlwczE4ZHE3bTFsZ2w5aCIsImVtYWlsT3ZlcmlmaWVkIjp0cnVlLCJlgmVugF9pZCI6IjY3MzMwZjMTLTcTZmItMTFlOS04ZTZhLTRkNjBlMmZmNmNkMyIsInRva2VuT3VzZSI6ImlkIiwiYTV0aF90aW3lIjoTNTU3MzY2MgE5LCJpc3MiOiJogHRwczpcL3wvY29nbml0by3pZHAuYTAtbm9ygGhlYTN0LTEuYW3hem9uYTgzLmNvbVwvYTAtbm9ygGhlYTN0LTFfajRFZ0JMTmRTIiwiY29nbml0bzp3c2VybmFtZSI6IjZmN2EwYWIyLTcyNgAtNgJmYS3hNGVhLThkNWRjNjQ4NTY3NSIsImV4cCI6MTU3NzM2OTYTOSwiaWF0IjoTNTU3MzY2MgE5LCJlbWFpbCI6InRlc3RzbmFwQHRpbWVycy3pbmMuY29tIn0
.
GR4Uo2EjWJwgtk7jFLPRB003A_bl0TlR-OoMLLlnB9KZBT93KCgbOQrhMV_4o0oHwjBm2p3zfCy0ZAzf7gIc_VbFKhTiK43pF2Uu850pPgepnnWmkUgWrpSVcnHFUs6SKTZUZsllJGQqr_gsoiYHgjYEkTgl60Mg3LUM7J4_vErB_7spi7yltgMumGaKiuFoL338My7YJOU3-BI4NBjGR86VQn4vcaHECOPSheTGmEW5B7jeTgk0MSAN0ykAHt6Sq7ng4Tg3nLEUcpeTA3Nt3Rw8S08glq_5ZGcyoJgAlsP7gCVg3kRNN9uJ_0eimkip7R6f02gsf_Ok8pT-IW4kag



  • . で分けられたtokenはそれぞれに意味があり、JWTは3つの要素で構成されています。

構成要素
要素の概要

ヘッダー
署名生成に使用したアルゴリズムや、トークンそのものに関する情報が格納している

ペイロード
クライアントとのやりとりに必要なクレームを格納している

電子署名
(ヘッダー+ペイロード+ 秘密鍵) を、アルゴリズムで暗号化した文字列

{Base64urlエンコードされたヘッダー}.{Base64urlエンコードされた ペイロード}.{電子署名}


  • ※ JWTはURIのクエリパラメーターなどに使用されることを想定しているので、URL-safeに表現するためにBase64urlエンコードした文字列となっています。



    • Base64エンコードの場合は +, /, = が含まれてしまい、URLパラメータとしては不適切になってしまいます。




JWTの構成要素詳細


1. ヘッダー


概要


  • 署名生成に使用したアルゴリズムや、トークンそのものに関する情報が格納されています。

  • キー名と値のペアで表現されたJSONをBase64urlエンコードした文字列となっています。


JWTヘッダーをデコードした値例

{

"typ": "JWT",
"alg": "HS256"
}


keyの種類

key
意味

typ
tokenの形式

alg
署名アルゴリズム (HS256: HMAC SHA-256)


2. ペイロード


概要



  • クライアント側とのやり取りで必要となる属性情報(=クレーム)が格納されています。

  • データはアプリケーション任意のものなので、必須となるものは存在しません

  • RFCにおいては、ペイロードに含める以下のような標準クレームが定義されています。(予約済みクレームといいます)


JWTペイロードをデコードした値例

{

"sub": "6f7a0ab2-7240-42fa-a4ea-xxxxxxxx",
"aud": "62vltt32xxxxxxxx",
"iss": "https://cognito-idp.ap-northeast-1.amazonaws.com/xxxxxxxxxx",
"exp": 1557369619,
"iat": 1557366019,
"auth_time": 1557366019,
"event_id": "67330f31-71fb-11e9-8e6a-xxxxxxxx", // カスタム,
"token_use": "id", // カスタム,
"cognito:username": "6f7a0ab2-7240-42fa-a4ea-xxxxxxxxxx" // カスタム,
"email": "testsnap@timers-inc.com" // カスタム
"email_verified": true, // カスタム
"phone_number": "090-1234-5678" // カスタム
}


keyの種類

予約済みクレーム
名称
説明

iss
Issuer
トークン発行者の識別子。一般的にアプリケーション固有となります.

sub
Subject
トークン主体の識別子。一般的にアプリケーション固有となります.

aud
Audience
トークンが意図している受信者の識別子。トークンを受け付ける受信者は、この値に自身が含まれるかを識別しなければなりません。もしaudクレームが存在し、かつ自身が含まれない場合、トークンを拒否しなければなりません。

exp
Expiration Time
トークンの有効期限。この期限以降の場合、トークンを受け付けてはなりません。有効期限は1970-01-01 00:00:00Zからの秒数を数値で指定しています(UNIX時間)[10]。

nbf
Not Before
トークンの開始日時。この期限以降の場合、トークンを受け付けてよい。秒数を数値で指定しています。

iat
Issued at
トークンの発行日時。秒数を数値で指定しています。

jti
JWT ID
発行者ごとトークンごとに一意な識別子。


3. 署名


概要



  • エンコード済みヘッダー + ピリオド(".") + エンコード済みペイロード + 秘密鍵 を、ヘッダー["alg"]の暗号化アルゴリズムで暗号化され生成されます。


  • 秘密鍵を利用しているので、生成者自身が改ざん検証を行うことができます。


HMAC-SHA256形式のコード例

HMAC-SHA256(

base64urlEncoding(header) + '.' +
base64urlEncoding(payload),
秘密鍵
)


  • 秘密鍵でハッシュ化する為、ヘッダーとペイロードを推測できても、署名を第三者が生成することが不可能になります。


JWTのメリット


  • DBへの接続削減


    • サーバーはヘッダーで渡されたトークンが正しいかだけを検証し、アクセスを許可するか判定することができます。

    • 認証に必要な情報は全てトークン内に格納されているので、データベースへの問い合わせを削減することができます。




JWTを利用する上でのセキュリティ注意点


ヘッダ情報algの改ざんによる脆弱性


内容


  • サーバーからJWTを受け取りデコードし、alg:noneに直して再度エンコードすると


    • => algが none なので署名の検証が行われずに、改ざんされたペイロードが利用されてしまいます。




対策


  • algの受け取る値をホワイトリスト形式で制限しましょう。


機密情報のやりとり


内容


  • 機密情報を含めたJWTを送信すると


    • => 悪いクライアントがデコードして情報を盗み取り悪用されてしまいます。




対策


  • クライアント側に見えてはいけない内容はJWTに含めないようにしましょう。


あとがき


  • JWTの概要についてまとめてみました。少しでも役に立てれば嬉しいですし、何か間違っていることなどあればコメントいただきたいです。

  • 最後までお読みいただき、ありがとうございました!