Note: JWT の仕様やそもそも論の話は触れません。どう使うか、何が出来るかしか書いていません。
JSON Web Token?
JSON Web Token とは、ざっくりいって署名の出来る JSON を含んだ URL Safe なトークンです。
署名とは、署名時に使った鍵を用いて、JSON が改ざんされていないかをチェック出来るようにすることです。
URL Safe とは、文字通り、URL に含めることの出来ない文字を含まないことです。
これだけだとよくわかりませんが、触り心地としては次のような性質があります。
- 発行者だけが、鍵を使ってトークンが正しいことを検証出来る。
- 暗号化ではないので、JSON の中身は誰でも見られる。
- 仕様的には、暗号化のオプションもあります。
- しかしながら、JSON の変更は出来ない。(改ざんをすると、検証時に失敗するので。)
- 全体的には、なんか変更できない JSON だと受けとっておけばよいかと
使われかた
この性質のため、認証サーバなどによく使われます。簡易フローとしては、
- クライアントは認証サーバに認証情報(よくあるのは user_id, password)を渡し、トークンを請求する。
- 認証サーバは認証情報が正しいことを確認して、秘密鍵を使って署名された JWT を発行する。
- この JWT は
user_id
とexpiration_date
を含む。
- クライアントはこの JWT を使って通常の API リクエストを行なう。
- サーバは、秘密鍵を使って JWT を検証し、
user_id
を JSON から取り出し、処理を行なう。
通常、このようなトークンを発行すると、user_id
を書き換えるだけで全てのユーザにアクセス出来てしまう致命的なセキュリティホールを作ってしまいます。
expiration_date
も同様で、これを書き換えるだけで無限に有効期限の切れないトークンが作れてしまいます。
しかし、JWT は「改ざん検証」が可能です。これを利用して、サーバでは検証が通らないトークンはすべて弾くようにします。そうすれば、事前にサーバが認めた user_id
と expiration_date
のみが通るようになります。
サーバは一度ユーザの認証情報を確認してからトークンを発行していますので、ここでの user_id
は信頼でき、ログインしているものと扱うことができます。
サーバが署名した情報だから、改ざんされていない(=検証が通る)限りは信頼して使ってよいということですね。
この強力な署名の仕組みの為に、トークンに含む内容にセンシティブにならずに、標準化された方法で簡単にトークンを発行出来ることが特徴です。
実際、このような仕組みを使わずに、セキュアにトークンを発行することは大変です。
素直にやれば、トークンをランダム生成し、サーバサイドでトークンと user_id
, expiration_date
を紐づけてストアし、トークンを受け取るたびに毎回フェッチして user_id
などを取り出す、という大仰な仕組みが必要になります。
トークンに、改ざんに対して安全に情報を保持させられることは、一見地味ですが強力な性質です。
ユースケース
JSON Web Token は様々な利用方法がありますので、色々見ると面白いと思います。
- OAuth のトークンとして
- Google の OAuth Token は JWT なので、Google API にトークン検証のリクエストをしなくてもトークンが検証できます。(公開鍵暗号を用いて署名していますので、クライアントには検証専用の鍵が配布されています。)
- メール認証のトークンとして
-
scope
をverify_email
としたuser_id
付きのトークンを発行
-
- パスワード忘れメール送付時のトークンとして
-
scope
をreset_password
としたuser_id
付きのトークンを発行
-
- サービスをまたいだ認証機構として
- 自社のサービス間で鍵を共有することで、かんたんに独立した認証サービスを作ることができます。
- 共有用URLとして
-
scope
を工夫することでどこまで guest に権限を持たせるかを決めることもできます。たとえば、scope = view(album#56)
などとしてid = 56
の Album の閲覧のみが可能な URL を発行するなど。 - ただし、URLがとんでもなく長くなるので短縮を噛ませるなど必須です。
-
使い勝手
JSON Web Token はライブラリがたくさんあります。
- Ruby: https://github.com/nov/json-jwt
- Python: https://github.com/rohe/pyjwkest
- Java: https://bitbucket.org/connect2id/nimbus-jose-jwt/wiki/Home
- PHP: https://github.com/ritou/php-Akita_JOSE
- Perl: https://github.com/xaicron/p5-JSON-WebToken
Objective-C もエンコード(発行)だけですが、ライブラリがあります。
- Objective-C: https://github.com/yourkarma/JWT
インターフェースとしてはどの言語も、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
- JSON Web Tokens - jwt.io : http://jwt.io/
- JWTについて簡単にまとめてみた - hiyosi's blog : http://hiyosi.tumblr.com/post/70073770678/jwt
- JSON Web Token (JWT) - OAuth.jp : http://oauth.jp/blog/2012/10/26/json-web-token-jwt/
- JSON Web Token (JWT) - Claims and Signing : http://self-issued.info/docs/draft-jones-json-web-token-01.html