JWT(JSON WEB TOKEN)入門

JWTは「JSON Web Token」の略です。JWTは今一番流行っているクロスドメイン認証ソリューションです。

1. クロスドメイン認証問題

ユーザ認証は一般的に下記の流れです。

① クライアントはサーバーへユーザ名、パスワードを送信する。
② サーバー側は認証を通りますと、セッション(session)に認証データ(ロール、ログイン時刻など)を保存する。
③ サーバーはクライアントへsession_idを返して、クライアントのCookieに書き込む。
④ クライアントはリクエストごとにCookieに保存されているsession_idをサーバーに渡す。
⑤ サーバー側はsession_idによって保存されたデータからユーザの権限を取得する。

このやり方は下記の課題があります。

  • サーバー性能問題
    ユーザ認証後、ユーザ情報を作成してサーバー上に保存します。通常はメモリに保存されますので、ユーザは多くなりますと、性能が落ちる可能性があります。
  • スケーラビリティ
    サーバー負荷によって台数を増やしたり減らしたりすることによって、セッションの維持、共有管理をしないといけないですので、DBなど共有サーバーで管理する必要です。
  • クロスドメイン対応
    シングルサイトの場合、特に問題がないですが、複数サイトをまたがる場合、セッション情報の共有が必要となりあす。例えば、AサイトとBサイトは某会社傘下のサービスです。ユーザはサイトAにログインして、サイトBも自動ログインする要件に対して、セッション情報をデータベースに書き込んで、リクエストを受けると、データベースからセッションを取得する必要です。

JWTを使って、サーバー側はセッションデータを保存せず、すべてのデータをクライアント側に保存する。リクエストごとにその情報をサーバーへ送信しますと、上記の課題は解決できます

2. JWTの原理

JWTはサーバー認証後、JSONオブジェクトを生成して、クライアント側に返します。

{
    "name": "takahasi",
    "role": "admin",
    "expiration": "2019-9-10 00:00:00"
}

その後、クライアントはサーバーへリクエストを送るたびに、このJSONオブジェクトをつけます。サーバー側はこの情報を使ってユーザ認証を行います。データ改ざんを防ぐために、サーバーはこのオブジェクトを生成するときに、署名もつけます。

サーバー側はセッションを保存しないと、ステートレスになりますので、スケーラビリティは簡単にできるようになります。

3. JWTのデータ構造

実際のJWTは下記のようです。

eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZXN0IiwiZXhwIjoxNTY3OTAxNDcyLCJpYXQiOjE1Njc5MDE0NTR9.sey05o9p_SniMc7mYKs63lRRz6KhELQ1qeDMUY-OL58wUqGDnRaGf8nQIW2v3YvTmOHN-8UqA-zP1rulVLBizA

長い文字列で、ピリオド「.」で3段を区切ります。3つの部分は下記の通りです。

Header
Payload
Signature

一行で書くと、

Hedaer.Payload.Signature

公式サイト(https://jwt.io/)を見れば、わかりやすいです。

3.1 Heaer

Header部分はJSONオブジェクトです。

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

alg属性は署名のアルゴリズムです。デフォルトは「HMAC SHA256」(HS256)です。
typ属性はトークンの種別です。
Header部分をBase64URLアルゴリズムで文字列に変換します。

3.2 Payload

PayloadもJSONオブジェクトです。
実際の送信データを保存します。7つの標準項目が定義されています。

No.keydetailcomment
1ississuer発行者
2expexpiration time失効日時
3subsubjectサブジェクト
4audaudience想定利用者
5nbfNot Before有効日時
6iatIssued At発行日時
7jtiJWT IDユニックID

注意:JWTデフォルトは暗号化されないため、誰でも読めますので、秘密情報はこの部分に入れないでください。
Payload部分もBase64URLで文字列に変換します。

3.3 Signature

Signature部分は前の2つの部分の署名となり、データ改ざんを防ぎます。
まず、秘密キーを指定して、このキーはサーバー側しかなく、ユーザに教えないこと。
次は、ヘッダに指定した署名アルゴリズム(デフォルトHMAC SHA256)で下記の算式で署名を生成すします。

 HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

署名を生成してから、Header、Payload、Signature3つの部分を「.」で区切って1つの文字列に結合してクライアント側に返します。

3.4 Base64URL

HeaderとPayloadの文字列変換はBase64URLとういアルゴリズムを使います。
このアルゴリズムはBase64アルゴリズムと似ていますが、若干違います。
JWTはトークンとして、URLに入れる可能性もあります。
例)https://api.example.com/?token=xxx
Base64の「+」「/」「=」はURLには特殊な意味があるため、Base64URLでは「=」を省略して、「+」を「-」に変換、「/」を「_」に変換します。

4. JWTの使い方

基本的な使い方は下記のイメージです。

①クライアントは認証リクエストを投げる。
②認証サーバーからトークンを返す。
③クライアントはそのトークンを利用してリソースサーバーをリクエストする。

クライアントはサーバーから返却したJWTはCookieに保存できますし、localStorageに保存できます。
クライアントからサーバーへのリクエストは必ずJWTをつけます。Cookieに入れて自動送信でも可能ですが、ドメインを跨がれないですので、一般的なやり方はHTTPリクエストのヘッダに「Authorization」に設定します。または、POSTリクエストのボディに入れても可能です。

Authorization: Bearer <token>

5. JWTの特徴

  • JWTは暗号化しない場合、秘密情報をJWTに書かないことです。
  • JWTは認証以外、情報交換でも使えます。JWTを有効に利用すれば、サーバー側DBの検索回数を下げることが可能です。
  • JWTはセッションを保存しないため、利用中token廃止、token権限変更などはできない。つまり、tokenを発行しますと、ロジックを追加しない限り、失効までずっと有効になります。
  • JWTには認証情報が入っていますので、漏洩したら、誰でもこのトークンの権限を取得できます。なりすましを防ぐために、JWTの有効期間を短くに設定したほうがよいと考えられます。重要な権限であれば、使用時に再度認証のほうが良いでしょう。
  • JWTはHTTPではなく、HTTPSを使うべきです。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA