SSOを導入したいという相談を受け、いまさらながらOpenID ConnectやJWTについて調べてみたのでメモ。
参考
こちらが非常にわかりやすい。
JWS
ヘッダー.ペイロード(本文).署名
と、それぞれURLセーフなBase64エンコードされたJSONがドットで結合されている。
この形式は、JWS(JSON Web Signature)としてRFC7515に規定。
IDトークンでは、署名が必須とされているため、通常こちらが使われる。
JWSヘッダー
Googleの認証結果には以下が含まれていた。
- alg: アルゴリズム
- kid: 鍵ID
- typ: メディアタイプ、通常
JWT
algがnoneの場合、署名を省略可能。仕様上は有効だが、運用時はアルゴリズムのnoneやHS(共通鍵暗号)は使わず、公開鍵暗号を使用したほうがいい模様。
Critical vulnerabilities in JSON Web Token libraries
JWSペイロード
クライアントに対し、認証サーバーから実際に渡されるデータ。
「Claim Set」と書いてあるのもどこかで見た。クレームと聞くと苦情かと思うが、ここでは請求の意味。
JWS署名
ヘッダー.ペイロード
を入力としたデジタル署名。署名形式はヘッダーのalg。
JWE
暗号化した形式、JWE(JSON Web Encryption)としてRFC7516に規定。
IDトークンとして使用する場合、JWSの ヘッダー.ペイロード.署名
を平文として暗号化したものが、暗号文として使われる。
今回は使わないので割愛。
JWK
JWSの署名やJWEの暗号化に、公開鍵暗号などの非対称鍵暗号が使用される場合、クライアント側で署名の検証や復号化を行うため、署名や暗号化に使われた鍵(公開鍵暗号での秘密鍵)と対になる鍵(公開鍵暗号での公開鍵)が必要となる。
その鍵の情報をJSON形式で表すための仕様。JWK(JSON Web Key)としてRFC7517に規定。
また、公開鍵認証の場合、以下が設定される模様。
- use: 公開鍵の使われ方, sig(JWS) OR enc(JWE)
- e: RSA暗号の公開指数(Public Exponent), 公開指数は65,537なので
AQAB
固定と思われる - n: RSA暗号のモジュラス(Modulus), 2つの素数p,qの積
- e, nともに整数値をOS2IP形式でバイナリ変換し、それをURLセーフなBase64に変換している
Google認証時の公開鍵
Googleの公開鍵は https://www.googleapis.com/oauth2/v3/certs で公開されている。
keysとして、いくつかの鍵情報が配列となっていた。
JWSヘッダーのalgおよびkidで検索し、公開鍵を特定する。
{ "keys": [ { "kid": "a06824b79e3982394d5ce7ac75bf92cba30a2e25", "e": "AQAB", "kty": "RSA", "alg": "RS256", "n": "tMrCJilHFRNB7Op6bhBSTpEEFCT4CM7zIOPT-HhjBhJ2bYahinC8FblyxE9rw889cS4eIAed9_614cQHUzv1lAgd3f-c0bonuMo_gGFJIOp5M4HlBz7yqimDDwYcSznSwtUziKM1pSCQr9IE-M-oNHd6ocXRhwKijzCIXIPvD4lPIjU5vR9rNziIume0AxfL8kAOIl2Rjcae8UmX24ydlLG1VGTiHuTcOzBZkGe5cAGHf4p4807PCihaSExWRQTbVrIfCIgBMehe1B99yf7ApKsHXVFN3pMsBso53jpL4XslJkOFI7SR0-gAvn89ieY5rGJ479srPDUBsZlSNtEiaw", "use": "sig" } ] }
JWT
IDトークンを発行する仕組み。認証/認可の文脈でいうと、認証した結果として返されるトークン。
JSON Web Tokenの略称で、RFC7519に規定。ちなみに、読み方は「jot」。
JSON形式のクレームをJWSのペイロードに設定、または暗号化してJWEの暗号文に設定したもの、となる模様。
Nested JWT
JWSでは署名、JWEでは暗号化しかできないため、両方を行いたい場合、どちらかの形式にもう片方を設定することとなる。
仕様では署名してから暗号化が必須となっているため、JWSを暗号化してJWEの暗号文に設定する。
Web経由ではhttps前提のため、暗号化は使われないっぽい?
とはいえ、通信プロトコルに依存はしていないと思われるので、暗号化されていない通信経路で使用する場合は、JWEやNested JWTで暗号化するのだろう。
Plaintext JWT
ヘッダに "alg": "none"
が指定されている場合、 Plaintext JWT
と呼ばれる。
そのまま、署名ないしは暗号化されていないJWTを指す。
仕様上有効とはいえ、通常はalgがnoneならエラーにするなどの対応が必要。
JWx
これらの仕様を総称し、JWxと呼ばれる。
OpenID Connectでの使われ方
OpenID Connectは、OAuth 2.0について、User IDの取得方法や、Profile APIの仕様について標準化したもの。
このUser IDの取得方法がIDトークン。そのIDトークンとして、JWTを使用することも記載されている。
振り返り
別途まとめてくれている人がいくらでもいるのに、わざわざこんなの書く意味はないかと思ったが、やってみるといい勉強になった。