JSON Web Tokenによる認証

◆ Live配信スケジュール ◆
サイオステクノロジーでは、Microsoft MVPの武井による「わかりみの深いシリーズ」など、定期的なLive配信を行っています。
⇒ 詳細スケジュールはこちらから
⇒ 見逃してしまった方はYoutubeチャンネルをご覧ください
【4/18開催】VSCode Dev Containersで楽々開発環境構築祭り〜Python/Reactなどなど〜
Visual Studio Codeの拡張機能であるDev Containersを使ってReactとかPythonとかSpring Bootとかの開発環境をラクチンで構築する方法を紹介するイベントです。
https://tech-lab.connpass.com/event/311864/

こんにちは。サイオステクノロジー技術部の武井です。

今回は、JSON Web Tokenの仕様に従ったアクセストークンをLinuxのコマンドラインで作成してみたいと思います。

その前に、JSON Web Tokenを説明したいと思います。

JSON Web Tokenとは?

JSON Web Tokenとは、JSONに電子署名を行い、必要に応じてそのJSONの検証を行い、認証可否を決定する仕様です。OpenIDやOAuthなどに用いられている標準的な仕様です。

セッションを使うことでも同様のことを実現ができますが、JSON Web Tokenの場合は、トークンそのものを検証することで認証可否を判断するので、セッションとは違い、サーバー側で何も持つ必要がありません。これにより、トークンを発行したホストと、トークンを検証するホストが別々でもよいのです。

よくある説明なのですが、イマイチわかりにくいと思います。

JSON Web Tokenの仕様に従って作成されたトークンは以下のようになっています。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e-KAnHN1YuKAnTrigJxudGFrZWnigJ19.97763576b44cbadea825195aa610b3b9ce71a52f228f3a2b41eba30e7e8350ad

長い文字列ですが、構成としては、ヘッダー、ペイロード、ヘッダーとペイロードをピリオドでつないで署名したものの3つをピリオドでつなげたものです。つまり以下のような感じです。

[ヘッダー].[ペイロード].[ヘッダーとペイロードをピリオドでつないで署名したもの]

ヘッダー、ペイロードをそれぞれ説明します。

ヘッダー

署名アルゴリズムとトークンのタイプを定義します。具体的には以下のようなJSONになります。

{ 
    “alg”: “HS256”, 
    “typ”: “JWT”
}

これは署名アルゴリズムはHS256、トークのタイプがJSON Web Tokenであることを表しています。トークンのタイプは他にもJWE(JSON Web Encryption)と言うものがあり、これは暗号化まで仕様として定義しているようです。しかしながら、今回は暗号化は行わず、あくまで署名だけですので、SSL等で暗号化することは必須となります。

ペイロード

JSON Web Tokenでやり取りするデータ本体です。例えばユーザー名だったり、認可情報だったり、ユーザーが自由に定義します。例えば以下のような感じです。

{ 
    “sub”: “ntakei”
}

これは、ユーザー名がntakeiのデータになります。ただ、何でも定義していいというわけではなく、幾つかのフィールド名はJSON Web Tokenの仕様によって予約されています。詳細はRFCを参照頂ければわかるのですが、例えば、expというフィールド名はトークンの有効期限として使われることが決まっているので、使ってはいけません。

次に、トークンを作成するまでの流れ、そしてそのトークンを検証するまでの流れを説明したいと思います。

トークン作成の流れ

トークン作成までの流れは以下のようになります。

Slide1

(1) ヘッダーをBase64 URL Encode

ヘッダーをBase64 URL Encodeします。Base64 URL EncodeとはBase64でエンコードした上で、更に以下の処理を施します。

 

  • +を-に置換
  • /を_に置換

これはURLに、+や/を乗せるとおかしな動作をする可能性があるからです。しかし、個人的には、トークンをURLに付与することがあるのかなと思っています。大抵は、HTTPリクエストヘッダのAuthorizationにセットするのが普通なのではないでしょうか?でもJSON Web Tokenの仕様なので、そのとおりにする必要があります。

(2) ペイロードをBase64 URL Encode

ヘッダーと同様にペイロードもBase64 URL Encodeします。

(3) HS256アルゴリズムとシークレットキーにより署名

(1)と(2)の値をピリオドでつなげて、その値のハッシュ値(不可逆で、その値からはもとの値が類推できないもの)を求めます。ハッシュ値は、HS256アルゴリズムと、サーバー側に保存されたシークレットキーで求めます。このハッシュ値を求めることを署名と言います。

そして、その(1)と(2)と(3)をそれぞれピリオドでつなげたものが、最終的にクライアントに渡されるトークンになります。

このトークンを受け取ったクライアントは、メモリなりデータベースなりローカルストレージなり永続化されるストレージに保存をして、認証で保護されたリソースにアクセスしたときは、ストレージから取得して、サーバーに渡します。

トークンを検証するまでの流れ

クライアントからトークンを受け取ったサーバーが、どうやって認証OKと判断するかを説明します。

Slide2

(1) HS256アルゴリズムとシークレットキーにより署名
クライアントから受け取ったトークンをピリオドで区切って、左から一つ目と二つ目(つまりヘッダーとペイロード)のハッシュ値を求めます。求め方は、先ほどと同じです。

(2) 一致しているかどうか比較
(1)で求めた値と、トークンをピリオドで区切ったものの中の一番右の部分(つまり、「トークン作成の流れ」でヘッダーとペイロードを署名したもの)が一致しているかどうかを比較します。これが一致していない場合は、認証情報が偽造もしくは改ざんされたものと判断し、認証NGとします。

アクセストークンを自分でつくってみる

Linuxのコマンドを使って、JSON Web Tokenの仕様に基づいたトークンを作って見たいと思います。

下記のようなJSONがあるとします。これらからトークンを作ります。

ヘッダー

{ 
    “alg”: “HS256”, 
    “typ”: “JWT”
}

ペイロード

{ 
    “sub”: “ntakei”
}

まずヘッダーをBase64 URL Encodeします。

# echo -n '{"alg":"HS256","typ":"JWT"}' | base64 | sed s/\+/-/ | sed -e 's/\//_/' | sed -E s/=+$//
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

まずbase64コマンドでbase64エンコードして、sedで+を-に置換、さらにsedで/を_に置換、さらにsedでBase64の最後に付加される=のパディング文字列を削除しています。

同様に、ペイロードもBase64 URL Encodeします。

# echo -n '{“sub”:“ntakei”}' | base64 | sed s/\+/-/ | sed -e 's/\//_/' | sed -E s/=+$//
e-KAnHN1YuKAnTrigJxudGFrZWnigJ19

次にヘッダーとペイロードをピリオドでつなげたものを、HS256アルゴリズムとシークレットキー(ここではsecret)でハッシュ値を求めます。

# echo -n 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e-KAnHN1YuKAnTrigJxudGFrZWnigJ19'  | openssl dgst -sha256 -hmac secret
97763576b44cbadea825195aa610b3b9ce71a52f228f3a2b41eba30e7e8350ad

今までの過程で得られた3つの値をピリオドでつなげます。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e-KAnHN1YuKAnTrigJxudGFrZWnigJ19.97763576b44cbadea825195aa610b3b9ce71a52f228f3a2b41eba30e7e8350ad

これがJSON Web Tokenの仕様に従ったトークンになります。

アバター画像
About 武井 宜行 269 Articles
Microsoft MVP for Azure🌟「最新の技術を楽しくわかりやすく」をモットーにブログtech-lab.sios.jp)で情報を発信🎤得意分野はAzureによるクラウドネイティブな開発(Javaなど)💻「世界一わかりみの深いクラウドネイティブ on Azure」の動画を配信中📹 https://t.co/OMaJYb3pRN
ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

8人がこの投稿は役に立ったと言っています。


ご覧いただきありがとうございます。
ブログの最新情報はSNSでも発信しております。
ぜひTwitterのフォロー&Facebookページにいいねをお願い致します!



>> 雑誌等の執筆依頼を受付しております。
   ご希望の方はお気軽にお問い合わせください!

Be the first to comment

Leave a Reply

Your email address will not be published.


*


質問はこちら 閉じる