-
Notifications
You must be signed in to change notification settings - Fork 0
MS_JWS
以下の内容で最終確認済み。
https://tools.ietf.org/html/rfc7515
-
ざっくり言って「MAC や署名付きの JWT = JWS」
-
JWT と言えば、だいたい、JWS の事を言う。
-
JWS は、暗号化ではなく署名なので、JSON の中身は誰でも見られる。
-
通常、発行者だけが秘密鍵で検証できるが、
- 秘密鍵(共通鍵)を使用すれば発行者だけが検証可能。
- 公開鍵を使用すれば誰でも検証可能。
-
OpenID Connect の ID Token などで利用されている。
OAuth 2.0 の Access Token としても使用されている。
移行メモ(正誤): 元ページの「秘密鍵を使用すれば発行者だけが検証可能」は、
文脈上 HMAC(共通鍵)を使う HS256 系の話である。
公開鍵暗号の「秘密鍵」で検証するのではなく、
発行者と検証者だけが知る共通鍵で MAC を検証する、という意味になる。
方式 生成に使う鍵 検証に使う鍵 検証できる者 HS256(MAC) 共通鍵 同じ共通鍵 鍵を持つ者だけ(=偽造もできる) RS256 / ES256(署名) 秘密鍵 公開鍵 誰でも(偽造はできない) 複数の RP にトークンを配る IdP は、必ず後者を使う。
JWS の基本的なヘッダ(≒ JWS Compact Serialization の場合の保護ヘッダ)には、
以下のものがある。
-
HS256
共通鍵で検証可能な HS256(HMAC using SHA-256 hash){ "alg": "HS256", "typ": "JWT" } -
RS256
公開鍵で検証可能な RS256(RSA using SHA-256 hash){ "alg": "RS256", "typ": "JWT" } -
ES256
公開鍵で検証可能な ES256(ECDSA using P-256 and SHA-256){ "alg": "ES256", "typ": "JWT" }
| パラメタ | 内容 | エンコーディング |
|---|---|---|
x5u |
X.509 URL | PEM エンコーディング |
x5c |
X.509 証明書チェーン | DER エンコーディングの base64(base64url ではない) |
x5t |
X.509 証明書 SHA-1 拇印 | DER エンコーディングの base64url |
x5t#S256 |
X.509 証明書 SHA-256 拇印 | DER エンコーディングの base64url |
補足(最新化):
x5t(SHA-1 拇印)は
SHA-1 の衝突困難性が破られている(2017 年 SHAttered)ため、
新規実装ではx5t#S256を使うこと。また、
jku/x5uは「鍵を取りに行く URL」であり、
攻撃者が制御する URL を書き込まれると
攻撃者の鍵で署名したトークンを受理してしまう。
取得先は許可リストで縛るか、そもそもサポートしないこと。
- その他のパラメタ
typcty
jku および / または x5u ヘッダ・パラメタをサポートする実装は、TLS が必要。
JWT を参照。
-
色々な署名・MAC アルゴリズムを使用して作成した署名
-
署名の検証キーの共有方法には以下の方法が有る。
-
参考 : OpenID Connect の署名検証 - Carpe Diem
http://christina04.hatenablog.com/entry/2015/01/27/131259
移行メモ(正誤): 元ページは「公開鍵①」「公開鍵①」と
同じ番号が 2 つ並んでいたので、②に改めた。
- 構成要素(ヘッダ、ペイロード(クレームセット)、署名)を
以下のように表現(エンコード)したもの。 - 以下の 2 つの表現(エンコード)方法があり、
どちらでも、構成要素は base64url でエンコードされる。
多くの場合は、この表現(エンコード)。
-
署名付きのデータを JSON(の Base64 URL Encode)形式で表現する。
-
「Base64」ではなく「Base64 URL」なので「
=」は含まれない。 -
例
ヘッダ.ペイロード(クレームセット).署名BASE64URL (UTF-8 (Header)) . BASE64URL (UTF-8 (Claim Set)) . BASE64URL (Signature)
※ 殆どの場合、こちらが使用されている。
移行メモ(正誤): 元ページの 3 行目は
BASE64URL (UTF-8 (Signature))となっていたが、
署名はバイト列であって UTF-8 テキストではないため、
BASE64URL (Signature)が正しい。
-
あまり市民権を獲得しているようには思えない表現(エンコード)。
- pure な JSON として表現されるフォーマット
- URL-Safe でもなければコンパクトでもない。
- MAC や署名を複数持てるといった違いがある。
-
Syntax
-
protected= BASE64URL(UTF8(保護ヘッダ)) -
signatures-
header= 非保護ヘッダ(JSON) -
payload= BASE64URL(ペイロード(クレームセット)) -
signature= BASE64URL(署名)
-
{ "payload":"<payload contents>", "signatures":[ {"protected":"<integrity-protected header 1 contents>", "header":"<non-integrity-protected header 1 contents>", "signature":"<signature 1 contents>"}, {"protected":"<integrity-protected header N contents>", "header":"<non-integrity-protected header N contents>", "signature":"<signature N contents>"}] } -
-
Example
-
Complete JWS JSON Serialization Representation
{ "payload": "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGF tcGxlLmNvbS9pc19yb290Ijp0cnVlfQ", "signatures":[ {"protected":"eyJhbGciOiJSUzI1NiJ9", "header": {"kid":"2010-12-29"}, "signature": "cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZ mh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjb KBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHl b1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZES c6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AX LIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw"}, {"protected":"eyJhbGciOiJFUzI1NiJ9", "header": {"kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"}, "signature": "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8IS lSApmWQxfKTUJqPP3-Kg6NU1Q"}] } -
JWS Using Flattened JWS JSON Serialization
MAC や署名が 1 つのみの場合は Flattened JWS JSON Serialization を使える。{ "payload": "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGF tcGxlLmNvbS9pc19yb290Ijp0cnVlfQ", "protected":"eyJhbGciOiJFUzI1NiJ9", "header": {"kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"}, "signature": "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8IS lSApmWQxfKTUJqPP3-Kg6NU1Q" }
-
JOSE ヘッダは、以下のメンバの和集合。
- JWS Compact Serialization の場合は、JOSE ヘッダ ≒ 保護ヘッダ。
- JWS JSON Serialization の場合は、
JOSE ヘッダ ≒ 保護ヘッダ and / or 非保護ヘッダ
MAC や署名によって完全性が保護されているヘッダ・パラメタを含む JSON オブジェクト。
- JWS Compact Serialization の場合、これは JOSE ヘッダ全体で構成される。
- JWS JSON Serialization の場合、
- これは JOSE ヘッダの 1 コンポーネント。
- 用例を解析してみると、JOSE ヘッダ中の
algパラメタが抽出されている。
-
これは、JWS JSON Serialization を使用する場合にのみ存在。
- JOSE ヘッダの 1 コンポーネントであるが、
- こちらは、署名の作成には利用されない。
-
完全性保護されていないヘッダ・パラメタを含む JSON オブジェクト。
-
用例を解析してみると、JOSE ヘッダ中の
kidパラメタが抽出されている。
(…kidが改ざんされると検証できなくなるだけなので、
保護しなくてもイイためとは言えそう)
補足: 元ページの推測は概ね正しい。
kidは「どの鍵か」を指すヒントであり、
改ざんされても検証に失敗するだけで、偽造の成立には繋がらない。ただしこれは「受信側が
kidを鍵の許可リストの索引としてのみ使う」
場合に限る。kidをそのままファイルパスや SQL に渡す実装では
パス トラバーサル・SQL インジェクションの入口になるため注意。
認証系であれば公開鍵暗号化方式の RS256(RSA using SHA-256 hash)が良い。
-
HS256 — キー付きハッシュである
alg=HS256(HMAC-SHA256)による MAC 付与 -
RS256 — 公開鍵暗号方式である
alg=RS256(RSA-SHA256)による署名を行う。 -
ES256 — 公開鍵暗号方式である
alg=ES256(ECDSA using P-256 and SHA-256)による署名を行う。- WebCrypto API で ECDSA の署名と検証を試してみる
https://qiita.com/tomoyukilabs/items/b346a71a920eb7a93501
- WebCrypto API で ECDSA の署名と検証を試してみる
-
JWAを確認
補足(最新化): 現在の推奨は次の通り。
alg位置づけ RS256相互運用性が最も高い。既定の選択肢 PS256RSASSA-PSS。RSA を使うなら本来こちらが望ましい ES256鍵・署名が短い。IoT やモバイルで有利 EdDSA(Ed25519)RFC 8037。実装ミスに強いが対応実装はやや限定的 HS256発行者と検証者が同一の閉じた系のみ none使用禁止(受理してもならない)
-
JWS を JOSE ヘッダ(= 保護ヘッダ)、ペイロード(クレームセット)の
JSON を生成し、- JOSE ヘッダ(= 保護ヘッダ)を UTF-8 のバイト文字列に変換し、BASE64url でエンコード。
- ペイロード(クレームセット)を UTF-8 のバイト文字列に変換し、BASE64url でエンコード。
-
BASE64url エンコード済みのヘッダとペイロード(クレームセット)をピリオドで連結、
-
上記をヘッダで指定したアルゴリズムで MAC・署名を生成し、
BASE64url エンコードし、当該要素をピリオドで連結する。
JWS Compact Serialization との差異は以下。
- JOSE ヘッダ(= 保護ヘッダ and / or 非保護ヘッダ)
- 非保護ヘッダは、MAC・署名の生成に使用されない。
- 必要に応じて、MAC・署名の生成を繰り返す。
-
JWS を JOSE ヘッダ(= 保護ヘッダ)、ペイロード(クレームセット)、
MAC・署名に分割し- JOSE ヘッダ(= 保護ヘッダ)を BASE64url でデコードし、UTF-8 に変換。
- ペイロード(クレームセット)を BASE64url でデコードし、UTF-8 に変換。
- MAC・署名を BASE64url でデコード。
-
署名方法(アルゴリズム、キー)を考慮して JWS の検証を行なう。
-
検証完了後、ペイロード(クレームセット)の JSON 内の有効期限の検証も行なう。
補足(順序が重要): 上の手順は
「ヘッダのalgを見てから検証方法を決める」ように読めるが、
それをやってはならない。正しくは「自分が受け入れる
algと鍵をあらかじめ決めておき、
ヘッダのalgがそれと一致するかを検査する」順序になる。
ヘッダの値を信じて分岐すると、alg: noneや
RS256→HS256 すり替え攻撃が成立する(JWT を参照)。また、署名検証より前にペイロードを業務ロジックへ渡さないこと。
JWS Compact Serialization との差異は以下。
- JOSE ヘッダ(= 保護ヘッダ and / or 非保護ヘッダ)
- 非保護ヘッダは、MAC・署名の検証に使用されない。
- 必要に応じて、MAC・署名の検証を繰り返す。
| アルゴリズム | RFC 7515 の付録 |
|---|---|
| HS256 | https://tools.ietf.org/html/rfc7515#appendix-A.1 |
| RS256 | https://tools.ietf.org/html/rfc7515#appendix-A.2 |
| ES256 | https://tools.ietf.org/html/rfc7515#appendix-A.3 |
移行メモ(正誤): 元ページは「具体例」節の見出しと
アンカーの対応がずれており、HS256 の項に RFC の A.2(RS256)が、
RS256 の項に A.1(HS256)が置かれていた。上表で正した。
すべての鍵に最低 128 ビットのエントロピーを使用する必要がある。
コンテキスト次第で、さらに多くのエントロピーが必要になる可能性がある。
- パブリック / プライベートキーペア、MAC キー、パディング値を
ランダムに生成する必要がある。 - 暗号鍵を生成するために適切な擬似乱数生成器(PRNG)を使用する。
(.NET では、PRNG として、
RNGCryptoServiceProviderを使用する。)
補足(最新化):
RNGCryptoServiceProviderは
**.NET 6 以降で非推奨(SYSLIB0023)**である。
現在はSystem.Security.Cryptography.RandomNumberGeneratorの
静的メソッドを使う。byte[] key = RandomNumberGenerator.GetBytes(32); // 256 bit
仕様の外だが、以下を使用できる。
-
保護
- MAC キーを保護する必要がある。
- MAC キーが破損すると、認証されたコンテンツの変更が検出されなくなる可能性がある。
-
発信元認証
鍵の出所の認証が必要。
-
保護
- 秘密鍵を保護する必要がある。
- 署名者の秘密鍵が侵害されると、攻撃者は署名者になりすますことができる。
-
発信元認証
データ発信元の認証が必要。
-
共通点
- 完全性チェックを提供
完全性値が計算されてからメッセージが変更されていないことを確認
- 完全性チェックを提供
-
相違点
セキュリティプロパティにはいくつかの重要な違いがある。
-
特定の状況下でのみ発信識別を提供するため、
第三者への発信を証明するために使用できない。- MAC キーが 2 つのエンティティにしか知られておらず、
受信者がメッセージを作成していないことが分かっている場合にのみ発信を判断できる。 - これは、メッセージが対称 MAC キーを知っている当事者のうちの
1 つによって生成されたという裏付けを提供するだけ。
- MAC キーが 2 つのエンティティにしか知られておらず、
-
秘密鍵と MAC キー
- 秘密鍵
単一のエンティティの手元にある - MAC キー
整合性の計算と検査に MAC キーを使用するすべてのエンティティの手元にある必要がある。
- 秘密鍵
※ HS256 はプレーンな HMAC で MAC ではない(ややこしい)。
移行メモ(正誤): この末尾の注記は誤りである。
HMAC は MAC の一種であり、HS256 は
「HMAC-SHA256 という方式で作られた MAC」に他ならない。
語 意味 MAC メッセージ認証符号という概念(共通鍵で完全性を保証する) HMAC ハッシュ関数から MAC を構成する方式(RFC 2104) HS256 HMAC-SHA256 を JOSE の alg名で呼んだもの元ページの意図はおそらく
「CMAC など、ブロック暗号ベースの MAC とは別物」という区別だと思われる。
署名は秘密鍵の保有者しか生成できないため、否認防止(第三者への証明)が成立する。
JWAを参照
.NETの署名・暗号化アルゴリズムの署名・暗号化アルゴリズムを
使用すると良い。
- HS256(HMAC using SHA-256 hash)
- HMACSHA256 クラス (System.Security.Cryptography)
https://learn.microsoft.com/dotnet/api/system.security.cryptography.hmacsha256
- HMACSHA256 クラス (System.Security.Cryptography)
-
RS256(RSA using SHA-256 hash)
- RSACryptoServiceProvider クラス (System.Security.Cryptography)
https://learn.microsoft.com/dotnet/api/system.security.cryptography.rsacryptoserviceprovider - Using RSACryptoServiceProvider for RSA-SHA256 signatures – .NET Security Blog
https://blogs.msdn.microsoft.com/shawnfa/2008/08/25/using-rsacryptoserviceprovider-for-rsa-sha256-signatures/
- RSACryptoServiceProvider クラス (System.Security.Cryptography)
-
ES256(ECDSA using P-256 and SHA-256)
- ECDsa クラス (System.Security.Cryptography)
https://learn.microsoft.com/dotnet/api/system.security.cryptography.ecdsa
- ECDsa クラス (System.Security.Cryptography)
-
PS256(RSASSA-PSS using SHA-256 and MGF1 with SHA-256)
補足(最新化): .NET Core 以降は、
RSACryptoServiceProviderや
ECDsaCngといった実装クラスを直接newせず、
RSA.Create()/ECDsa.Create()を使うのが正しい。
Windows / Linux / macOS で適切な実装が選択される。using var rsa = RSA.Create(2048); byte[] sig = rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); // RS256 // PS256 なら RSASignaturePadding.Pssなお、実務で JWS を自作する必要はほとんどない。
.NET ならMicrosoft.IdentityModel.JsonWebTokens(JsonWebTokenHandler)を使う。
以下が参考になる。
- 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 側での検証ができている。
上記のように、RFC を正確に理解していないと JWT ライブラリ作成は難しいが、
JSON Web Tokens - jwt.io などの検証サイトを使用して検証できれば、
及第点に達していると言える。
以下のように検証できる。
補足(取り扱い注意): 検証サイトに
本物のトークンや秘密鍵を貼り付けてはならない。
動作確認はテスト用の鍵とダミーのクレームで行うこと。
- 左ペイン(Encoded)に JWT の文字列を貼り付ける。
- すると、入力した JWT から、ペイン(Decoded)の Header、Payload に
自動的に表示がなされる。 - 次に、上部 ALGORITHM selectbox から、Header に表示された
algと
同じアルゴリズムを選択する。 - 最後に、VERIFY SIGNATURE に、署名の検証に使用するキーを入力する
(HS256 の場合と RS256 の場合で異なる)。
HS256 は非常に単純で、署名に使用したキーの Base64(Base64Url)表現を指定する。

RS256 は署名に使用した秘密鍵に対応する公開鍵を指定する。
私は、X.509証明書を利用したので、
OpenSSLで公開鍵を取得して、それを貼り付けた所、検証ができた。
ポイントは、
-----BEGIN PUBLIC KEY------ 「公開鍵」
-----END PUBLIC KEY-----
と、ヘッダ・フッタ部分も貼り付ける必要がある所だろうか。

- JWTの生成と検証 - Open 棟梁 Wiki
https://opentouryo.osscons.jp/index.php?JWT%E3%81%AE%E7%94%9F%E6%88%90%E3%81%A8%E6%A4%9C%E8%A8%BC
-
RFC 7515 - JSON Web Signature (JWS)
https://tools.ietf.org/html/rfc7515 -
JSON Web Signature (JWS) 日本語訳
https://openid-foundation-japan.github.io/draft-ietf-jose-json-web-signature-14.ja.html -
複雑に関係しあうJWTまわりの仕様を見る: JWS (JSON Web Signature) - 理系学生日記
http://kiririmode.hatenablog.jp/entry/20170225/1488020088 -
jose-jwt(ライブラリ)
-
- JWA - JWS用(JWA)
- .NETの署名・暗号化アルゴリズム
Tags: 移行, IT国際標準, プログラミング, 通信技術, 認証基盤, クレームベース認証, 暗号化
このWikiは「Open棟梁Project」,「OSSコンソーシアム 開発基盤部会」によって運営されています。