[[Open棟梁Project>http://opentouryo.osscons.jp/]] - [[マイクロソフト系技術情報 Wiki>http://techinfoofmicrosofttech.osscons.jp/]] -[[戻る>クレームベース認証]] * 目次 [#ld8342fd] #contents *概要 [#yfb13271] JWTとはJSON Web Tokenの略でjot(ジョット)と発音する。 **仕様 [#u3914621] -JSONのアサーション(クレーム)を生成するための仕様 -Base64 URL Encodeしたヘッダ、クレームセット等を「.」で連結 --このため、url-safeであり、Webでの取り扱いが楽。 --言語毎のライブラリも整っており、相互運用が容易。 **用途 [#s26d45ab] -暗号化により、鍵でペイロード(クレームセット)の改ざんチェック可能。 -この特徴のため、仲介者を伴う(改竄・盗聴の危険性がある)情報のやり取りに利用される。 --主に、認証サーバから返されるトークンに使われる。 --実際、[[OAuth]] 2.0 拡張や[[OpenID Connect]]などで使われている。 **種類 [#ba527d8c] JWTを作る方法としてJWSとJWE、もしくは両方を使った方法がある。 ***JWS [#o550b442] JWSは、暗号化ではなく署名なので、JSON の中身は誰でも見られる。~ 通常、発行者だけが秘密鍵で検証できるが、公開鍵を使用すれば誰でも検証が可能。 ***JWE [#i16b516e] JWEは、暗号化のオプション。 **注意 [#ob14e5e6] 「Base64」ではなく「Base64 &color(red){URL};」なので「=」は含まれない。 *構造 [#ad27d98c] **構成要素 [#q01f4062] 以下の要素から構成される。 ここの詳細は、[[RFC>#t002076b]]を参照。 個別に、 -[[OpenID Connect]]の[[IDトークン(クレーム)>OpenID Connect#ofb73c59]] -[[JWT生成プログラムの作成方法の参考サイト>JWT#e11d0494]] などを参照のこと。 ***ヘッダ [#m9c6f99a] 署名検証のために利用するもの。 基本的なもので、 -秘密鍵で検証可能なHS256(HMAC using SHA-256 hash)のJWT { "alg": "HS256", "typ": "JWT" } -公開鍵で検証可能なRS256(RSA using SHA-256 hash)のJWT { "alg": "RS256", "typ": "JWT" } とか。 ***ペイロード(クレームセット) [#m5b94cda] -[[予約済みクレーム>https://openid-foundation-japan.github.io/draft-ietf-oauth-json-web-token-11.ja.html#ReservedClaimName]]~ 以下すべて、使用は任意 (OPTIONAL)。 --"iss" : Issuer クレーム --"sub" : (Subject) クレーム --"aud" : (Audience) クレーム --"exp" : (Expiration Time) クレーム --"nbf" : (Not Before) クレーム --"iat" : (Issued At) クレーム --"jti" : (JWT ID) クレーム --"typ" : (Type) クレーム -パブリッククレーム --JWTの利用者によって自由に定義できる。 --衝突を避けるために、 ---IANA JSON Web Token Claim Registry に登録するか、 ---耐衝突性を持つ名前空間を含むパブリック名にすべき。 -プライベートクレーム --JWTの作成者と利用者の合意のものとで、~ 予約済みでもパブリッククレーム名でもないプライベートクレーム名を利用可能。 --ただし、衝突の可能性があるため、慎重に使用する必要がある。 -サンプル { "sub": "1234567890", "name": "John Doe", "admin": true } ***署名 [#f7edb04c] -色々な暗号化アルゴリズムを使用して作成した署名 -署名の検証キーの共有方法には以下の方法が有る。 --検証用エンドポイントを使用する。 --[[JWK>#t3bd8497]]を使用する。 --[[X.509証明書>証明書]]を使用する。 -参考 : OpenID Connect の署名検証 - Carpe Diem~ http://christina04.hatenablog.com/entry/2015/01/27/131259 --検証方法①:Googleの検証用エンドポイントを利用する --検証方法②:IdP(Google)の提供している公開鍵を使って自分で検証する ---公開鍵①:[[JWK>#t3bd8497]](JSON Web Key)を使う ---公開鍵①:[[X.509証明書>証明書]]を使う **JWTの種類 [#j5dabc60] ***JWS [#md583102] 署名されたJWT -署名付きのデータを JSON (の Base64 URL Encode) 形式で表現するための仕様 -多くの場合は JSON Payload に対して署名するケースで利用される。 -OpenID Connect の ID Tokenなどで利用されている。 BASE64URL (UTF-8 (Header)) . BASE64URL (UTF-8 (Claim Set)) . BASE64URL (UTF-8 (Signature)) ***JWE [#y75c2692] 暗号化されたJWT -暗号化されたデータを JSON (の Base64 URL Encode) 形式で表現するための仕様 -暗号化された[[SAML]] アサーションを Connect に移行するユースケースなどが想定される。 ヘッダー.キー.初期ベクター.暗号文.認証タグ BASE64URL (UTF-8 (JWE Protected Header)) . BASE64URL(JWE Encrypted Key) . BASE64URL(JWEInitialization Vector) . BASE64URL(JWE Ciphertext) . BASE64URL(JWE Authentication Tag) ***プレーンJWT [#of14a838] [[ヘッダ>#m9c6f99a]]内のalgはnone = {“alg”: “none”} 。 ヘッダー.ペイロード. BASE64URL (UTF-8 (Header)) . BASE64URL (UTF-8 (Claim Set)) . *JWTの作成と検証手順 [#dd514c38] -JWT を扱えるライブラリは沢山ある。 -署名・暗号化は特定用途であれば、1パターン実装すればイイので自作も可能。 -検証・復号化は網羅性を高めることが難しいので、ライブラリを使用する。 --OpenID Connect の JWT の署名を自力で検証してみると見えてきた公開鍵暗号の実装の話 - Qiita~ http://qiita.com/bobunderson/items/d48f89e2b3e6ad9f9c4c **ライブラリ [#n981cbc3] -JSON Web Token の効用 - Qiita~ http://qiita.com/kaiinui/items/21ec7cc8a1130a1a103a -WebCrypto APIでJSON Web Tokenの検証を試してみる - Qiita~ http://qiita.com/tomoyukilabs/items/faa66805a440f4b30cfb |項番|言語|ライブラリのURL|h |0|JavaScript|https://www.w3.org/TR/WebCryptoAPI/| |1|Ruby|https://github.com/nov/json-jwt| |2|Python|https://github.com/rohe/pyjwkest| |3|Java|https://bitbucket.org/nimbusds/nimbus-jose-jwt/wiki/Home| |4|PHP|https://github.com/ritou/php-Akita_JOSE| |5|Perl|https://github.com/xaicron/p5-JSON-WebToken| |6|Objective-C|https://github.com/yourkarma/JWT| |7|.NETなら|Nugetからメジャーな奴を入れる。| **JWTの作成手順 [#pfa9f0dd] ***概要 [#wbf0fb96] -JWSまたはJWEの手順に従って生成 -入れ子になったJWTの場合には[[ヘッダ>#m9c6f99a]]の”cty”の値に”JWT”を指定 ***手順(JWS) [#p744be69] -[[ヘッダ>#m9c6f99a]]を生成し、UTF-8のバイト文字列に変換し、BASE64urlエンコード。 -クレームセットを生成し、UTF-8のバイト文字列に変換し、BASE64urlエンコード。 -BASE64urlエンコード済みの[[ヘッダ>#m9c6f99a]]とクレームセットを~ ピリオドで連結する、UTF-8バイト文字列に変換し、BASE64urlエンコード。 -上記をヘッダで指定した暗号化プロバイダで暗号化(ハッシュ or 暗号化) **JWTの検証手順 [#r8923712] ***手順 [#ib69bb72] -JWTを[[ヘッダ>#m9c6f99a]]、クレームセット、署名に分割しBASE64urlでデコード。 -[[ヘッダ>#m9c6f99a]]から種類(JWT、JWS、JWE)、暗号化プロバイダを確認する。 -[[署名方法>#f7edb04c]](暗号化プロバイダ、キー)を考慮してJWTの検証を行なう。 -検証完了後、クレームセット内の有効期限の検証も行なう。 ***検証サイト [#s7ab5c53] -JSON Web Tokens - jwt.io~ https://jwt.io/ *その他の仕様 [#vf919761] **JWK [#t3bd8497] JWS や JWE などで利用する公開鍵(JWK : JSON Web Key)を JSON 形式で表現するための仕様 -OpenID Connect Discovery をサポートしている IdP は公開鍵を JWK Set 形式で公開していることが多い。 -参考 --WebCrypto APIでJSON Web Tokenの検証を試してみる - Qiita~ http://qiita.com/tomoyukilabs/items/faa66805a440f4b30cfb ---Google OpenID Connectの場合、署名を検証するために必要となるJWKがWebサイト上で公開されている。 ---一定時間ごとに更新されるため、署名の検証時にはその都度JWKの内容をWebサイトから取得する。~ https://www.googleapis.com/oauth2/v2/certs **JWA [#y4a514dc] JWS や JWE で利用される各アルゴリズムおよびそれらの識別子を定義している仕様 -・・・ *ユースケース [#neb31e45] **認証用途 [#yd304024] -JWT(JSON Web Token)を使った認証を試みる | 69log~ https://blog.kazu69.net/2016/07/30/authenticate_with_json_web_token/ -JWTを認証用トークンに使う時に調べたこと - Carpe Diem~ http://christina04.hatenablog.com/entry/2016/06/07/123000 -JWT(Json Web Token)を利用したWebAPIでのCredentialの受け渡しについて | I am mitsuruog~ http://blog.mitsuruog.info/2014/08/jwtjson-web-tokenwebapicredential.html ***[[OpenID Connect]]のIDトークン [#o5f70766] [[コチラ>OpenID Connect#ofb73c59]]を参照。 ***[[OAuth]] 2.0のアクセストークン [#f9d1b3ca] [[コチラ>OAuthによる外部ログイン(認証)の研究#yf9cec19]]を参照。 ***シングルサインオン(SSO) [#qc19ebd8] -シングルサインオン - Wikipedia~ https://ja.wikipedia.org/wiki/%E3%82%B7%E3%83%B3%E3%82%B0%E3%83%AB%E3%82%B5%E3%82%A4%E3%83%B3%E3%82%AA%E3%83%B3 --近年は、SAMLアサーションやJWTアサーション([[OpenID Connect]]の[[IDトークン>OpenID Connect#ofb73c59]])~ によって、クレデンシャル伝えてSSOを実現する方式が一般的になってきている。 -JWTを使った簡易SSOで徐々にシステムをリニューアルしている話~ http://www.slideshare.net/TsuchiKazu/jwt-ssopepabotech --ショップ(Webアプリ)とカート(WebAPI+SPA)を分離し、~ tempストアをサイト間で共有しないで、認証情報を共有するSSOを実現したい。 --JWTにより、以下を跨いだ認証が可能に。 ---サーバー(Webアプリ・WebAPI)間 ---クライアント(ブラウザ)・サーバー(Webアプリ・WebAPI)間 --また、その後の、 ---マイクロサービス化にも対応可能になる。~ サービスの多様化、フロントエンドの多極化 ---認証情報以外の共有したい情報にも利用することができる。~ この場合、JWEを使用する可能性がある(HTTPSなら不要だが)。 -JWT(JSON Webトークン)を使用したシングルサインオンの設定 – Zendesk Support~ https://support.zendesk.com/hc/ja/articles/203663816-JWT-JSON-Web%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3-%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%9F%E3%82%B7%E3%83%B3%E3%82%B0%E3%83%AB%E3%82%B5%E3%82%A4%E3%83%B3%E3%82%AA%E3%83%B3%E3%81%AE%E8%A8%AD%E5%AE%9A **メール着信確認トークン [#uc4b4ccb] 以下でメール着信確認トークンを使用するようなケースで利用する事で、~ トークンをtempストアに格納して、後に比較するような実装が不要になる。 -アカウント確認(E-mail confirmation) -パスワード・リセット **共有用URL [#w567a950] -OneDriveのファイル・フォルダ共有にも利用されている。 -URLにオブジェクトに対する[[ACL・ACE]]的なモノをJWTアサーションに同梱。 -サービスが認証したユーザがオブジェクトに対するアクセス許可を持っているか、[[ACL・ACE]]から確認する。 **RFC [#k7337bf9] ***Assertion Framework for OAuth 2.0 Client Authentication and Authorization Grants [#e7d6a65b] https://tools.ietf.org/html/rfc7521 -[[OAuth]] 2.0 を拡張するアサーションの仕様 --Client Authentication で Client Credentials として使うアサーションの仕様 --Authorization Codeグラント種別のAccess Token と交換するアサーションの仕様 -単体では利用できず、後の2つのサブ仕様~ (RFC7522(SAMLアサーション)、7523(JWTアサーション))~ の共通部分を抽象化した仕様になっている。 ***JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants [#gc47e455] https://tools.ietf.org/html/rfc7523 JWT を [[RFC 7521(上記)>#e7d6a65b]] の アサーション として利用するための仕様 **参考 [#lcb2fd20] -JSON Web Token の効用 - Qiita~ http://qiita.com/kaiinui/items/21ec7cc8a1130a1a103a -JWTによるJSONに対する電子署名と、そのユースケース | Developers.IO~ http://dev.classmethod.jp/server-side/json-signing-jws-jwt-usecase/ *.NETのJWTライブラリ [#c4fe6111] **相性がある模様 [#l9bea68e] ***[[System.IdentityModel.Tokens.JwtSecurityTokenHandler>https://msdn.microsoft.com/ja-jp/library/system.identitymodel.tokens.jwtsecuritytokenhandler.aspx]] [#y171da32] Microsoft Open Technologiesによって開発された、~ JSON Web Token Handler For the Microsoft .Netというライブラリ。 下記が参考になる。 -IdM実験室~ http://idmlab.eidentity.jp -- [JWT/OAuth]Service Accountを使ってGoogle APIを利用する①, ②~ ---http://idmlab.eidentity.jp/2015/01/jwtoauthservice-accountgoogle-api.html ---http://idmlab.eidentity.jp/2015/01/jwtoauthservice-accountgoogle-api_5.html 上記は、ResourcesOwnerであるユーザが介在することなく~ ClientがResourcesServerのAPIを利用するようなユースケースらしく、~ 以下の様な、grant_typeで、AccessTokenを取得して、WebAPIにアクセスする。 -grant_type:~ http://oauth.net/grant_type/jwt/1.0/bearer --TenantContextID、AppPrincipalId、SymmetricKey を使用して、 --JWTを投げると、AccessTokenが返ってくるflowのgrant_typeらしい。 この時、Googleの秘密鍵のキー長は1024bitだが、~ このライブラリは最低でも2048bitを要求しているため、 >相互運用が不可だったらしい。 恐らく、色々なライブラリ間の実装差異で~ 相互運用が難しくなるようなケースがあると思う。 ***[[Microsoft.Owin.Security.Jwt.JwtFormat>https://msdn.microsoft.com/ja-jp/library/microsoft.owin.security.jwt.jwtformat.aspx]] [#ib881924] 以下の2メソッドのインターフェイスを確認すると、~ 引数・戻り値に、Microsoft.Owin.Security.AuthenticationTicketが在ったり、~ .NET技術と結合度が高く、相互運用には向かないように見える。 -[[JwtFormat.Protect メソッド>https://msdn.microsoft.com/ja-jp/library/dn450167.aspx]] -[[JwtFormat.Unprotect メソッド>https://msdn.microsoft.com/ja-jp/library/dn450160.aspx]] **検索結果 [#r4ac23c8] -NugetやWebを検索した所、以下の2ライブラリの利用者が多い。 -ダウンロード数を確認した所、System.IdentityModel.Tokens.Jwtが優勢。 ***JSON Web Token (JWT) implementation for .NET [#o8ee7ae2] -NuGet Gallery | JWT 1.3.4~ https://www.nuget.org/packages/JWT/ Version Historyを参照。 ***System.IdentityModel.Tokens.Jwt [#f8161509] 以前は、JSON Web Token Handler For the Microsoft .Netという表示名だったようだが、~ version 05-00からは、パッケージ名(=名前空間)と同じ表示名になっている。~ ライセンスはMITだが、ソースコードをGithubやCodePlex上に確認できない・・・。 上記の、BCL入りしているJwtSecurityTokenHandlerが含まれる名前空間より~ 一つ下の階層のJWT系の追加ライブラリを格納する名前空間であるもよう。 必要に応じて、追加でNugetから取得する必要がある。 -NuGet Gallery | System.IdentityModel.Tokens.Jwt~ https://www.nuget.org/packages/System.IdentityModel.Tokens.Jwt/ 詳しくは、Version Historyを参照。 **自作ライブラリについて [#v028206c] 以下を考慮して開発可能。 ***用途 [#b90af93a] -認証など、特定用途の署名・暗号化、検証・復号化レベルであればであれば自作ライブラリで良い。 -正しく署名・暗号化できていれば、他のライブラリでも検証・復号化が可能。 ***相互運用(検証・復号化) [#dfbab710] 他のライブラリでも検証・復号化が可能かどうかは、~ [[JSON Web Tokens - jwt.io>https://jwt.io/]]などのサイトを使用して確認すると良い。 ***Base64urlエンコード・デコード [#n0909b67] このライブラリも必要になる。 -【C#】Base64urlエンコード・デコード - Qiita~ http://qiita.com/hukatama024e/items/b1352cabcd85948511c3 >RFC4648に条件付きでパディング外すなどの難しい処理が~ あるようなので、ライブラリを使用するほうが良いかもしれない~ (Microsoft.Owin.Securityのicrosoft.Owin.Security.DataHandler.Encoderにライブラリがある)。 ***[[署名・暗号化アルゴリズム>.NETの署名・暗号化アルゴリズム]] [#p4042a8b] 特定用途であれば、上記サイトにも、.NETにも実装されている -KeyedHashAlgorithm --RS256(HMAC using SHA-256 hash) ---HMACSHA256 クラス (System.Security.Cryptography)~ https://msdn.microsoft.com/ja-jp/library/system.security.cryptography.hmacsha256.aspx -AsymmetricAlgorithm --RS256(RSA using SHA-256 hash) ---RSACryptoServiceProvider クラス (System.Security.Cryptography)~ https://msdn.microsoft.com/ja-jp/library/system.security.cryptography.rsacryptoserviceprovider.aspx ---Using RSACryptoServiceProvider for RSA-SHA256 signatures – .NET Security Blog~ https://blogs.msdn.microsoft.com/shawnfa/2008/08/25/using-rsacryptoserviceprovider-for-rsa-sha256-signatures/ [[署名・暗号化アルゴリズム>.NETの署名・暗号化アルゴリズム]]を使用すると良い。 認証であれば公開鍵暗号化方式のRS256(RSA using SHA-256 hash)が良い。 ***脆弱性 [#j8e0d191] 実装に脆弱性を作らないように注意する。 -JWS 実装時に作りがちな脆弱性パターン - OAuth.jp~ http://oauth.jp/blog/2015/03/16/common-jws-implementation-vulnerability/ ざっくり、 -alg を "none"に改竄された場合、検証でtrueにするな。 -alg を "HMAC-SHA*"に改竄された場合、検証でtrueにするな。 ということらしい。 後者は、 -公開鍵暗号方式 (RSA / ECDSA) から共通鍵暗号方式 (HMAC) に差し替え、 -「公開鍵文字列を共通鍵として利用して」署名を生成することで、 検証でtrueになるJWTを生成できてしまう模様。 特定用途の自作ライブラリであれば、~ 署名と検証のalgは固定にしておくのも良いと考える。 ***参考サイト [#e11d0494] ちなみに、 -C#と.NETを使ってJsonWebTokenをRS256で署名して作成する方法 - ぺぷしのーげん~ http://www.pepsinogen.blog/entry/2016/06/19/C%23%E3%81%A8_NET%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6JsonWebToken%E3%82%92RS256%E3%81%A7%E7%BD%B2%E5%90%8D%E3%81%97%E3%81%A6%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95 は、 -ToXmlString、FromXmlStringのXML文字列を使用できるか? -この署名の方法と、ヘッダの表記はあっているか? が記載されていない。 また、 -oauth - Is there a JSON Web Token (JWT) example in C#? - Stack Overflow~ http://stackoverflow.com/questions/10055158/is-there-a-json-web-token-jwt-example-in-c は、いくつか誤りがあるようで、RS256は、HMACSHA256ではない。 故に、(実際にGoogle側での検証ができているので)こちらのほうが参考になる。 -IdM実験室: [JWT/OAuth]Service Accountを使ってGoogle APIを利用する②~ http://idmlab.eidentity.jp/2015/01/jwtoauthservice-accountgoogle-api_5.html ココを見ると、 -{ alg = "RS256", typ = "JWT" }と言うヘッダで、 -RSACryptoServiceProvider + X509Certificate2の署名を行っており、 これで、実際にGoogle側での検証ができている。 秘密鍵・公開鍵のキーペアを、 -ToXmlStringmethod()メソッドによって生成するか? --一応、[[RFC 3275 - XML-Signature Syntax and Processing - 4.4 The KeyInfo Element>https://www.ietf.org/rfc/rfc3275.txt]]で標準規格化されているもよう。 --そもそも、「KeyInfo Element(DSAKeyValue, RSAKeyValue Elementなど)」サポートされているか? -X509Certificate2 クラスを使用してX.509 証明書から取得するか? 検討(検証)する必要が出てくる。 (・・・RFCを正確に理解していないとライブラリ作成は難しい)。 *参考 [#p90217f2] -JWTについて簡単にまとめてみた - hiyosi's blog~ https://hiyosi.tumblr.com/post/70073770678/jwt%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E7%B0%A1%E5%8D%98%E3%81%AB%E3%81%BE%E3%81%A8%E3%82%81%E3%81%A6%E3%81%BF%E3%81%9F **RFC [#t002076b] -IETF JOSE WG と OAuth WG から一気に9本の RFC が! - OAuth.jp~ http://oauth.jp/blog/2015/05/20/jose-and-oauth-assertion-rfcs/ ***JOSE WG [#z5dc6cf2] jose : Javascript Object Signing and Encryption -RFC 7515 - JSON Web Signature (JWS)~ https://tools.ietf.org/html/rfc7515 -RFC 7516 - JSON Web Encryption (JWE)~ https://tools.ietf.org/html/rfc7516 -RFC 7517 - JSON Web Key (JWK)~ https://tools.ietf.org/html/rfc7517 -RFC 7518 - JSON Web Algorithms (JWA)~ https://tools.ietf.org/html/rfc7518 -RFC 7520 - Examples of Protecting Content~ Using JSON Object Signing and Encryption (JOSE)~ https://tools.ietf.org/html/rfc7520 ***OAuth WG [#vdd1ecf0] -RFC 7519 - JSON Web Token (JWT)~ https://tools.ietf.org/html/rfc7519 -RFC 7521 - Assertion Framework for~ OAuth 2.0 Client Authentication and Authorization Grants~ https://tools.ietf.org/html/rfc7521 -RFC 7522 - Security Assertion Markup Language (SAML) 2.0 Profile~ for OAuth 2.0 Client Authentication and Authorization Grants~ https://tools.ietf.org/html/rfc7522 -RFC 7523 - JSON Web Token (JWT) Profile~ for OAuth 2.0 Client Authentication and Authorization Grants~ https://tools.ietf.org/html/rfc7523 ***公開資料 | OpenID ファウンデーション・ジャパン [#n96a7959] -JSON Web Token (JWT)~ https://openid-foundation-japan.github.io/draft-ietf-oauth-json-web-token-11.ja.html ---- Tags: [[:認証基盤]], [[:クレームベース認証]], [[:暗号化]]