JSON Web Token の効用

  • 728
    いいね
  • 2
    コメント

Note: JWT の仕様やそもそも論の話は触れません。どう使うか、何が出来るかしか書いていません。

JSON Web Token?

JSON Web Token とは、ざっくりいって署名の出来る JSON を含んだ URL Safe なトークンです。
署名とは、署名時に使った鍵を用いて、JSON が改ざんされていないかをチェック出来るようにすることです。
URL Safe とは、文字通り、URL に含めることの出来ない文字を含まないことです。

これだけだとよくわかりませんが、触り心地としては次のような性質があります。

  1. 発行者だけが、鍵を使ってトークンが正しいことを検証出来る。
  2. 暗号化ではないので、JSON の中身は誰でも見られる。
    • 仕様的には、暗号化のオプションもあります。
  3. しかしながら、JSON の変更は出来ない。(改ざんをすると、検証時に失敗するので。)
  4. 全体的には、なんか変更できない JSON だと受けとっておけばよいかと

使われかた

この性質のため、認証サーバなどによく使われます。簡易フローとしては、

  1. クライアントは認証サーバに認証情報(よくあるのは user_id, password)を渡し、トークンを請求する。
  2. 認証サーバは認証情報が正しいことを確認して、秘密鍵を使って署名された JWT を発行する。
    • この JWT は user_idexpiration_date を含む。
  3. クライアントはこの JWT を使って通常の API リクエストを行なう。
  4. サーバは、秘密鍵を使って JWT を検証し、user_id を JSON から取り出し、処理を行なう。

通常、このようなトークンを発行すると、user_id を書き換えるだけで全てのユーザにアクセス出来てしまう致命的なセキュリティホールを作ってしまいます。
expiration_date も同様で、これを書き換えるだけで無限に有効期限の切れないトークンが作れてしまいます。

しかし、JWT は「改ざん検証」が可能です。これを利用して、サーバでは検証が通らないトークンはすべて弾くようにします。そうすれば、事前にサーバが認めた user_idexpiration_date のみが通るようになります。

サーバは一度ユーザの認証情報を確認してからトークンを発行していますので、ここでの user_id は信頼でき、ログインしているものと扱うことができます。

サーバが署名した情報だから、改ざんされていない(=検証が通る)限りは信頼して使ってよいということですね。

この強力な署名の仕組みの為に、トークンに含む内容にセンシティブにならずに、標準化された方法で簡単にトークンを発行出来ることが特徴です。

実際、このような仕組みを使わずに、セキュアにトークンを発行することは大変です。
素直にやれば、トークンをランダム生成し、サーバサイドでトークンと user_id, expiration_date を紐づけてストアし、トークンを受け取るたびに毎回フェッチして user_id などを取り出す、という大仰な仕組みが必要になります。

トークンに、改ざんに対して安全に情報を保持させられることは、一見地味ですが強力な性質です。

ユースケース

JSON Web Token は様々な利用方法がありますので、色々見ると面白いと思います。

  • OAuth のトークンとして
    • Google の OAuth Token は JWT なので、Google API にトークン検証のリクエストをしなくてもトークンが検証できます。(公開鍵暗号を用いて署名していますので、クライアントには検証専用の鍵が配布されています。)
  • メール認証のトークンとして
    • scopeverify_email とした user_id 付きのトークンを発行
  • パスワード忘れメール送付時のトークンとして
    • scopereset_password とした user_id 付きのトークンを発行
  • サービスをまたいだ認証機構として
    • 自社のサービス間で鍵を共有することで、かんたんに独立した認証サービスを作ることができます。
  • 共有用URLとして
    • scope を工夫することでどこまで guest に権限を持たせるかを決めることもできます。たとえば、scope = view(album#56) などとして id = 56 の Album の閲覧のみが可能な URL を発行するなど。
    • ただし、URLがとんでもなく長くなるので短縮を噛ませるなど必須です。

使い勝手

JSON Web Token はライブラリがたくさんあります。

Objective-C もエンコード(発行)だけですが、ライブラリがあります。

インターフェースとしてはどの言語も、JSON と秘密鍵を渡したらよしなにしてくれるような感じです。お手軽。
何も考えなくて良いのが JWT の良い所。

# エンコード
JSON::JWT.new({foo: "bar"}).sign(key, algorithm)
# デコード
JSON::JWT.decode(jwt_string, key)
// エンコード
[JWT encodePayload:@{@"foo": @"bar"} withSecret:@"secret"];

Conclusion

  • JWT には実質改ざん不可能な情報を含めることが出来る。
    • この性質のため、認証サーバから返されるトークンに使われる。
  • JWT を上手く使うことで安全な通信 / 連携を実現出来る。
  • JWT を扱えるライブラリが沢山ある。
  • JWT は URL Safe なので、取り扱いが楽。
  • トークンはとりあえず JWT を使っておけばいいだろう、という安心感がある(私見)
  • 本文では触れませんでしたが、公開鍵暗号での署名であれば「署名用の鍵」と「検証用の鍵」を分けることが可能です。JWT発行サーバには署名用の鍵を持たせ、他のサーバには検証用の鍵を持たせることもできます。

References