0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JWSの概要まとめ

Posted at

実務でJWSによって保護されたJWTを扱う機会があったのですが、あれから時間が経過して忘れてしまっていることが多いため、JWSについてまとめることにしました。

記事の内容は RFC7515 JSON Web Signature (JWS) を元にJWSの概要をまとめました。
この記事では以下の点についてまとめています。

  1. JWSは何か
  2. JWSの構成要素
  3. JWSの3つの形式
  4. JWSの作成/検証
  5. JWSとJWTの関係

JWSの概要

JWS(JSON Web Signature)は、デジタル署名やメッセージ認証コード(MAC)によってデータを保護し、改ざん検知を可能にする仕組みです。保護対象のデータはJSONオブジェクトである必要はなく、任意のデータとすることができます。JWSは文字列またはJSONオブジェクトとして表現されます。このうち、JWT(JSON Web Token)で使われる表現は文字列です。

用語説明

本記事を読む上で参考にしてください。
これらはRFC7515の 2. Terminologyで定義されています。

JWS Protected Header

デジタル署名やMACによって保護されるJSONオブジェクト。
データ保護に使用された暗号操作などに関する情報を含む。
JWSでは name/value のペアを Header Parameter という。
含むことのできる Header Parameter の詳細はRFC7515 4. JOSE Headerを参照。

JWS Unprotected Header

デジタル署名やMACによって保護されないJSONオブジェクト。
含むことのできる Header Parameter は JWS Protected Headerとほとんど変わらないが、
"alg" などセキュリティ上重要な Header Parameter を含めることは推奨されない。
JWS JSON Serialization形式のJWSでのみ使われる。

JWS Payload

データをエンコードして得られるオクテットシーケンス(8ビットのバイト列)。
デジタル署名やMACによって保護される。
データはJSONである必要はなく、任意のデータとすることが可能

JWS Signing Input

デジタル署名やMACを求めるために必要な値で、
以下を処理して得られるオクテットシーケンス。

ASCII(BASE64URL(UTF8(JWS Protected Header)) || '.' || BASE64URL(JWS Payload))

JWS Signature

JWS Protected HeaderとJWS Payloadに対するデジタル署名またはMACのこと。

JWSの構成要素

JWSは以下の要素の組み合わせで構成されます。

  • JWS Protected Header
  • JWS Unprotected Header
  • JWS Payload
  • JWS Signature

どれをどう組み合わせるかはJWSの形式によって異なります。

JWSの形式

形式は3つあります。

1. JWS Compact Serialization

JWSをASCII文字列として表現する方法。
コンパクトでURLに含めても安全なのが特徴

BASE64URL(UTF8(JWS Protected Header)) || '.' ||
BASE64URL(JWS Payload) || '.' ||
BASE64URL(JWS Signature)

2. JWS JSON Serialization

JWSをJSONオブジェクトとして表現する方法。
複数のデジタル署名やMACでデータを保護できるが、コンパクトさやURL安全性が最適化されていない。JSONを構成する “protected” と “header” は必ずどちらか一つは存在しなければならない。
2つの構文がある

2.1. General JWS JSON Serialization Syntax

複数のデジタル署名やMACでデータを保護できる。より一般的な構文。

{
  "payload":"<BASE64URL(JWS Payload)>",
  "signatures":[
    {"protected":"<BASE64URL(UTF8(JWS Protected Header))>",
      "header":<JWS Unprotected Header>,
      "signature":"<BASE64URL(JWS Signature)>"},
     ...
    {"protected":"<BASE64URL(UTF8(JWS Protected Header))>",
      "header":<JWS Unprotected Header>,
      "signature":"<BASE64URL(JWS Signature)>"}]
}
2.2 Flattened JWS JSON Serialization Syntax

1つのデジタル署名またはMACでデータを保護する構文。
よりコンパクトな表現が可能

{
  "payload":"<BASE64URL(JWS Payload)>",
  "protected":"<BASE64URL(UTF8(JWS Protected Header))>",
  "header":<JWS Unprotected Header>,
  "signature":"<BASE64URL(JWS Signature)>"
}

次のセクションでそれぞれのJWSを作成します。

JWSの作成

ここではデータ保護方法として、署名スキーム RSASSA-PKCS1-v1_5 とハッシュ関数 SHA-256 を使った方法を取り上げますが、他の方法においても JWS Signature の作成/検証を除いて処理が共通しています。他の方法でJWSを作成するフローを確認したい方は Appendix A. JWS Examples を参照ください。

データは以下のJSONオブジェクトとし、署名スキーム RSASSA-PKCS1-v1_5 とハッシュ関数SHA-256を使ってデータを保護します。

{"iss":"joe",
 "exp":1300819380,
 "http://example.com/is_root":true}

必要なデータを準備する

3つの形式に共通で必要なデータは次の3つです。(JWS JSON Serialization 形式のJWSでは、 “kid” をJWS Unprotected Header に含めることが可能ですが、説明を簡単にするために JWS Protected Header に含めることにし、 JWS Unprotected Header は省略します)

  • BASE64URL(UTF8(JWS Protected Header))
  • BASE64URL(JWS Payload)
  • BASE64URL(JWS Signature)

BASE64URL(UTF8(JWS Protected Header)) を作成する
JWT Protected Header は以下のJSONオブジェクトです。
”alg” は必須要素で、どのような方法で保護するかを表します。
”kid” はデジタル署名の検証に必要な公開鍵を特定するための値です。

{"alg":"RS256",
 "kid":"1dbe06b5d7c2a7c044563061ff0fea37740b86bc"}

このJSONの文字列表現をUTF-8エンコードしてオクテットシーケンスに変換します。
(見やすさのために途中で改行を入れています)

[123, 34, 116, 121, 112, 34, 58, 34, 74, 87, 84, 34, 44, 13, 10, 32, 
34, 97, 108, 103, 34, 58, 34, 82, 83, 50, 53, 54, 34, 44, 13, 10, 32, 
34, 107, 105, 100, 34, 58, 34, 49, 100, 98, 101, 48, 54, 98, 53, 100, 
55, 99, 50, 97, 55, 99, 48, 52, 52, 53, 54, 51, 48, 54, 49, 102, 102, 
48, 102, 101, 97, 51, 55, 55, 52, 48, 98, 56, 54, 98, 99, 34, 125]

このオクテットシーケンスを base64url エンコードして文字列に変換します。
以降、これを header として参照します。

eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJSUzI1NiIsDQogImtpZCI6IjFkYmUwNmI1ZDdjMmE3YzA0NDU2MzA2MWZmMGZlYTM3NzQwYjg2YmMifQ

BASE64URL(JWS Payload) を作成する
JWS Payload はデータをエンコードして得られるオクテットシーケンスです。今回はデータがJSONなのでUTF-8でエンコードします。(途中で改行を入れています)

[123, 34, 105, 115, 115, 34, 58, 34, 106, 111, 101, 34, 44, 13, 10, 32, 
34, 101, 120, 112, 34, 58, 49, 51, 48, 48, 56, 49, 57, 51, 56, 48, 44, 
13, 10, 32, 34, 104, 116, 116, 112, 58, 47, 47, 101, 120, 97, 109, 112, 
108, 101, 46, 99, 111, 109, 47, 105, 115, 95, 114, 111, 111, 116, 34, 58, 
116, 114, 117, 101, 125]

このJWS Payloadを base64url エンコードします。
以降、これを payload として参照します。

eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ

BASE64URL(JWS Signature) を作成する
JWS Signature を作成するために、まず JWS Signing Input を求めます。
JWS Signing Input は header と payload をドット(”.”)で結合した文字列をASCIIエンコードして得られるオクテットシーケンスです。(途中で改行を入れています)

[101, 121, 74, 48, 101, 88, 65, 105, 79, 105, 74, 75, 86, 49, 81, 105, 76, 
65, 48, 75, 73, 67, 74, 104, 98, 71, 99, 105, 79, 105, 74, 83, 85, 122, 73, 
49, 78, 105, 73, 115, 68, 81, 111, 103, 73, 109, 116, 112, 90, 67, 73, 54, 
73, 106, 70, 107, 89, 109, 85, 119, 78, 109, 73, 49, 90, 68, 100, 106, 77, 
109, 69, 51, 89, 122, 65, 48, 78, 68, 85, 50, 77, 122, 65, 50, 77, 87, 90, 
109, 77, 71, 90, 108, 89, 84, 77, 51, 78, 122, 81, 119, 89, 106, 103, 50, 
89, 109, 77, 105, 102, 81, 46, 101, 121, 74, 112, 99, 51, 77, 105, 79, 105, 
74, 113, 98, 50, 85, 105, 76, 65, 48, 75, 73, 67, 74, 108, 101, 72, 65, 105, 
79, 106, 69, 122, 77, 68, 65, 52, 77, 84, 107, 122, 79, 68, 65, 115, 68, 81, 
111, 103, 73, 109, 104, 48, 100, 72, 65, 54, 76, 121, 57, 108, 101, 71, 70, 
116, 99, 71, 120, 108, 76, 109, 78, 118, 98, 83, 57, 112, 99, 49, 57, 121, 
98, 50, 57, 48, 73, 106, 112, 48, 99, 110, 86, 108, 102, 81]

署名で使う秘密鍵は、RFC7515 A.2. Example JWS Using RSASSA-PKCS1-v1_5 SHA-256 のJWK(JSON Web Key)形式で表現されたRSA鍵を使用します。

鍵の内容(長いので折りたたみます)
 {"kty":"RSA",
  "n":"ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddx
       HmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMs
       D1W_YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb_7OMg0LOL-bSf63kpaSH
       SXndS5z5rexMdbBYUsLA9e-KXBdQOS-UTo7WTBEMa2R2CapHg665xsmtdV
       MTBQY4uDZlxvb3qCo5ZwKh9kG4LT6_I5IhlJH7aGhyxXFvUK-DWNmoudF8
       NAco9_h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQ",
  "e":"AQAB",
  "d":"Eq5xpGnNCivDflJsRQBXHx1hdR1k6Ulwe2JZD50LpXyWPEAeP88vLNO97I
       jlA7_GQ5sLKMgvfTeXZx9SE-7YwVol2NXOoAJe46sui395IW_GO-pWJ1O0
       BkTGoVEn2bKVRUCgu-GjBVaYLU6f3l9kJfFNS3E0QbVdxzubSu3Mkqzjkn
       439X0M_V51gfpRLI9JYanrC4D4qAdGcopV_0ZHHzQlBjudU2QvXt4ehNYT
       CBr6XCLQUShb1juUO1ZdiYoFaFQT5Tw8bGUl_x_jTj3ccPDVZFD9pIuhLh
       BOneufuBiB4cS98l2SR_RQyGWSeWjnczT0QU91p1DhOVRuOopznQ",
  "p":"4BzEEOtIpmVdVEZNCqS7baC4crd0pqnRH_5IB3jw3bcxGn6QLvnEtfdUdi
       YrqBdss1l58BQ3KhooKeQTa9AB0Hw_Py5PJdTJNPY8cQn7ouZ2KKDcmnPG
       BY5t7yLc1QlQ5xHdwW1VhvKn-nXqhJTBgIPgtldC-KDV5z-y2XDwGUc",
  "q":"uQPEfgmVtjL0Uyyx88GZFF1fOunH3-7cepKmtH4pxhtCoHqpWmT8YAmZxa
       ewHgHAjLYsp1ZSe7zFYHj7C6ul7TjeLQeZD_YwD66t62wDmpe_HlB-TnBA
       -njbglfIsRLtXlnDzQkv5dTltRJ11BKBBypeeF6689rjcJIDEz9RWdc",
  "dp":"BwKfV3Akq5_MFZDFZCnW-wzl-CCo83WoZvnLQwCTeDv8uzluRSnm71I3Q
       CLdhrqE2e9YkxvuxdBfpT_PI7Yz-FOKnu1R6HsJeDCjn12Sk3vmAktV2zb
       34MCdy7cpdTh_YVr7tss2u6vneTwrA86rZtu5Mbr1C1XsmvkxHQAdYo0",
  "dq":"h_96-mK1R_7glhsum81dZxjTnYynPbZpHziZjeeHcXYsXaaMwkOlODsWa
       7I9xXDoRwbKgB719rrmI2oKr6N3Do9U0ajaHF-NKJnwgjMd2w9cjz3_-ky
       NlxAr2v4IKhGNpmM5iIgOS1VZnOZ68m6_pbLBSp3nssTdlqvd0tIiTHU",
  "qi":"IYd7DHOhrWvxkwPQsRM2tOgrjbcrfvtQJipd-DlcxyVuuM9sQLdgjVk2o
       y26F0EmpScGLq2MowX7fhd_QJQ3ydy5cY7YIBi87w93IKLEdfnbJtoOPLU
       W0ITrJReOgo1cq9SbsxYawBgfp_gh6A5603k2-ZQwVK0JKSHuLFkuQ3U"
 }

このJWKから秘密鍵を作成し、RSA署名関数に秘密鍵、SHA-256、JWS Signing Inputを与えると、以下の JWS Signature が得られます。(途中で改行を入れています)

[119, 64, 125, 226, 172, 102, 132, 43, 208, 154, 241, 32, 52, 150, 161, 85, 
14, 183, 119, 57, 18, 101, 9, 68, 227, 163, 109, 166, 186, 224, 105, 164, 
191, 170, 251, 192, 123, 155, 238, 185, 215, 177, 120, 118, 23, 41, 224, 
100, 145, 49, 238, 60, 53, 73, 109, 174, 73, 119, 0, 148, 176, 164, 55, 33, 
181, 187, 0, 52, 194, 213, 102, 220, 132, 186, 99, 72, 231, 103, 62, 80, 
191, 77, 64, 100, 91, 242, 229, 205, 111, 8, 62, 3, 92, 1, 175, 67, 122, 
126, 150, 247, 35, 138, 211, 37, 216, 144, 71, 24, 225, 245, 7, 38, 249, 
138, 199, 63, 40, 246, 137, 196, 1, 181, 129, 126, 41, 179, 234, 76, 102, 
217, 14, 28, 118, 241, 218, 193, 29, 49, 156, 234, 242, 167, 17, 8, 176, 
166, 173, 55, 211, 250, 212, 168, 9, 202, 145, 52, 245, 60, 118, 9, 184, 
246, 55, 40, 74, 149, 76, 138, 36, 196, 144, 249, 21, 54, 18, 64, 221, 195, 
246, 140, 239, 42, 235, 105, 255, 196, 7, 189, 146, 194, 183, 75, 91, 50, 4, 
241, 100, 206, 239, 221, 19, 64, 240, 153, 143, 153, 13, 109, 159, 85, 30, 
230, 61, 67, 127, 45, 180, 58, 182, 34, 178, 109, 179, 129, 105, 173, 106, 
203, 69, 215, 108, 215, 8, 90, 135, 197, 12, 111, 70, 175, 57, 27, 187, 206, 
4, 185, 162, 235, 193, 84, 177, 243, 25, 42, 184, 86]

このJWS Signatureを base64url エンコードします。
以降、これを signature として参照します。

d0B94qxmhCvQmvEgNJahVQ63dzkSZQlE46NtprrgaaS_qvvAe5vuudexeHYXKeBkkTHuPDVJba5JdwCUsKQ3IbW7ADTC1WbchLpjSOdnPlC_TUBkW_LlzW8IPgNcAa9Den6W9yOK0yXYkEcY4fUHJvmKxz8o9onEAbWBfimz6kxm2Q4cdvHawR0xnOrypxEIsKatN9P61KgJypE09Tx2Cbj2NyhKlUyKJMSQ-RU2EkDdw_aM7yrraf_EB72SwrdLWzIE8WTO790TQPCZj5kNbZ9VHuY9Q38ttDq2IrJts4FprWrLRdds1whah8UMb0avORu7zgS5ouvBVLHzGSq4Vg

準備した header, payload, signature から、3つの形式のJWSを作成します。

JWS Compact Serialization

準備した header, payload, signature を先頭から順番にドット(’.’)で結合すると
JWS Compact Serialization 形式のJWSの完成です。(途中で改行を入れています)

eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJSUzI1NiIsDQogImtpZCI6IjFkYmUwNmI1ZDdjMmE3YzA0NDU2MzA2MWZmMGZlYTM3NzQwYjg2YmMifQ
.
eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ
.
d0B94qxmhCvQmvEgNJahVQ63dzkSZQlE46NtprrgaaS_qvvAe5vuudexeHYXKeBkkTHuPDVJba5JdwCUsKQ3IbW7ADTC1WbchLpjSOdnPlC_TUBkW_LlzW8IPgNcAa9Den6W9yOK0yXYkEcY4fUHJvmKxz8o9onEAbWBfimz6kxm2Q4cdvHawR0xnOrypxEIsKatN9P61KgJypE09Tx2Cbj2NyhKlUyKJMSQ-RU2EkDdw_aM7yrraf_EB72SwrdLWzIE8WTO790TQPCZj5kNbZ9VHuY9Q38ttDq2IrJts4FprWrLRdds1whah8UMb0avORu7zgS5ouvBVLHzGSq4Vg

Flattened JWS JSON Serialization Syntax

JSONオブジェクトの protected, payload, signature 要素の値として、それぞれ header, payload, signature を使うことで完成です。

{
  "payload":"eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ",
  "protected":"eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJSUzI1NiIsDQogImtpZCI6IjFkYmUwNmI1ZDdjMmE3YzA0NDU2MzA2MWZmMGZlYTM3NzQwYjg2YmMifQ",
  "signature":"d0B94qxmhCvQmvEgNJahVQ63dzkSZQlE46NtprrgaaS_qvvAe5vuudexeHYXKeBkkTHuPDVJba5JdwCUsKQ3IbW7ADTC1WbchLpjSOdnPlC_TUBkW_LlzW8IPgNcAa9Den6W9yOK0yXYkEcY4fUHJvmKxz8o9onEAbWBfimz6kxm2Q4cdvHawR0xnOrypxEIsKatN9P61KgJypE09Tx2Cbj2NyhKlUyKJMSQ-RU2EkDdw_aM7yrraf_EB72SwrdLWzIE8WTO790TQPCZj5kNbZ9VHuY9Q38ttDq2IrJts4FprWrLRdds1whah8UMb0avORu7zgS5ouvBVLHzGSq4Vg"
}

General JWS JSON Serialization Syntax

今回は一つのデジタル署名でデータを保護しているので以下のようにして完成です。デジタル署名やMACが複数存在する場合は、それぞれに対応するJSONオブジェクトを signatures 要素に追加します。

{
  "payload":"eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ",
  "signatures":[
    {
      "protected":"eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJSUzI1NiIsDQogImtpZCI6IjFkYmUwNmI1ZDdjMmE3YzA0NDU2MzA2MWZmMGZlYTM3NzQwYjg2YmMifQ",
      "signature":"d0B94qxmhCvQmvEgNJahVQ63dzkSZQlE46NtprrgaaS_qvvAe5vuudexeHYXKeBkkTHuPDVJba5JdwCUsKQ3IbW7ADTC1WbchLpjSOdnPlC_TUBkW_LlzW8IPgNcAa9Den6W9yOK0yXYkEcY4fUHJvmKxz8o9onEAbWBfimz6kxm2Q4cdvHawR0xnOrypxEIsKatN9P61KgJypE09Tx2Cbj2NyhKlUyKJMSQ-RU2EkDdw_aM7yrraf_EB72SwrdLWzIE8WTO790TQPCZj5kNbZ9VHuY9Q38ttDq2IrJts4FprWrLRdds1whah8UMb0avORu7zgS5ouvBVLHzGSq4Vg"
    }
  ]
}

JWSの検証

signature の検証

RS256で保護された場合、デジタル署名の検証は、SHA-256ハッシュ関数を使用するように設定された署名検証機RSASSA-PKCS1-V1_5-VERIFY ((n, e), M, S)に以下のデータを渡して行います。

  • M:JWS Signing Input (前の例と同じため省略)
  • S:JWS Signature(前の例と同じため省略)
  • (n, e):公開鍵

公開鍵はweb上のエンドポイントから取得できます。公開鍵は証明書やJWKの形式で提供されることがあります。例として、firebase は証明書facebookはJWKを提供します。

先ほどのJWKの n と e から公開鍵を作成すると以下の値が得られます。
(途中で改行を入れています)

"-----BEGIN PUBLIC KEY-----\n
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAofgWCuLjybRlzo0tZWJj\n
NiuSfb4p4fAkd/wWJcyQoTbji9k0l8W26mPddxHmfHQp+Vaw+4qPCJrcS2mJPMEz\n
P1Pt0Bm4d4QlL+yRT+SFd2lZS+pCgNMsD1W/YpRPEwOWvG6b32690r2jZ47soMZo\n
9wGzjb/7OMg0LOL+bSf63kpaSHSXndS5z5rexMdbBYUsLA9e+KXBdQOS+UTo7WTB\n
EMa2R2CapHg665xsmtdVMTBQY4uDZlxvb3qCo5ZwKh9kG4LT6/I5IhlJH7aGhyxX\n
FvUK+DWNmoudF8NAco9/h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXp\n
oQIDAQAB\n-----END PUBLIC KEY-----\n"

署名の検証にはライブラリを使うことが多いと思います。署名・検証に利用できるライブラリはJWT公式ページにまとまっています。

具体的な署名検証フローが知りたい人は RFC3447 8.2.2 Signature verification operation を確認ください。(時間がある時にまとめるかも)

signature が複数ある場合について
RFC7515 5.2. Message Signature or MAC Validationによれば、すべての signature の検証に失敗した場合はJWSを無効として扱うが、その全ての検証に成功するべきなのか、そのうちのどの検証に成功するべきなのかの判断はアプリケーションに委ねるとしています。

他の検証項目について
RFC7515 5.2. Message Signature or MAC Validation では signature の検証以外にも検証項目が列挙されていますが、ライブラリを使う場合は気にしなくて良さそうなため割愛します。

JWT と JWS の関係

RFC7519 1. Introduction では、JWTは以下のように説明されています。

JWTs encode claims to be transmitted as a JSON [RFC7159] object that is used
as the payload of a JSON Web Signature (JWS) [JWS] structure or 
as the plaintext of a JSON Web Encryption (JWE) [JWE] structure, 
enabling the claims to be digitally signed or integrity protected with a 
Message Authentication Code (MAC) and/or encrypted. JWTs are always represented 
using the JWS Compact Serialization or the JWE Compact Serialization.

このことから、以下の条件をすべて満たすJWSはJWTであると言えます。

  • JWSの形式が JWS Compact Serialization
  • payload に含まれるデータがJSONオブジェクト(このJSONオブジェクトをJWTではJWT Claims Set といいます)
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?