* 仕様書

[REFS[
- [1] '''[CITE@en[RFC 7469 - Public Key Pinning Extension for HTTP]] ([TIME[2015-05-05 21:00:37 +09:00]] 版) <https://tools.ietf.org/html/rfc7469#section-2.1.4>'''
- [20] [CITE@en[RFC 7469 - Public Key Pinning Extension for HTTP]] ([TIME[2015-05-05 21:00:37 +09:00]] 版) <https://tools.ietf.org/html/rfc7469#section-2.5>
- [22] [CITE@en[RFC 7469 - Public Key Pinning Extension for HTTP]] ([TIME[2015-05-05 21:00:37 +09:00]] 版) <https://tools.ietf.org/html/rfc7469#section-3>
- [31] [CITE[RFC Errata Report]] ([TIME[2015-06-05 21:00:41 +09:00]] 版) <http://www.rfc-editor.org/errata_search.php?rfc=7469>
- [42] [CITE@en[RFC 7469 - Public Key Pinning Extension for HTTP]] ([TIME[2015-05-05 21:00:37 +09:00]] 版) <https://tools.ietf.org/html/rfc7469#section-5>
]REFS]

* 意味

[4] [[利用者エージェント]]が [[Pin Validation]] の失敗を報告する[['''べき''']]ことと、
その報告先 [[URL]] を指定するものです [SRC[>>1]]。

* 構文

[36] 値は、 [[URL]] です。

;; [35] [[RFC]] では構文はなぜか明記されていません。

[11] 指定する[[ホスト]]が本[[応答]]の[[ホスト]]と一致している必要はありません [SRC[>>1]]。

[37] [[相対URL]]が指定された時の[[基底URL]]や、 [[URL]] 
として正しくない文字列が指定された時の解釈は不明です。

* 文脈

[2] [[PKP]] [[ヘッダー]]に指定できます。

[3] 省略可能です [SRC[>>1]]。

* 処理

[6] [[URL]] が指定されている場合で [[Pin Validation]] に失敗した時は、
報告を指定された [[URL]] に送信する[['''べきです''']] [SRC[>>1, >>22]]。
[[利用者エージェント]]は報告するよう最善の努力を尽くすべきですが、
例外的状況で報告できなくても構いません [SRC[>>1]]。

[EG[
[12] 例えば報告先が [[Pinning Validation]] その他の[[証明書]]の検証に失敗するなら、
[[接続]]を中止しなければなりません [SRC[>>1]]。
]EG]

;; [34] [[PKP]] の処理の項も参照。

[18] 任意の他サイトに報告を送って良いのかどうかは謎です。とはいえ同じホストに送ってもおそらく
[[Pin Validation]] エラーになることは変わらないので、違うホストに送る必要があるのでしょうが...

;; [19] [[DDoS]] に使えそうですが、 [CODE(HTMLe)@en[[[img]]]] や [CODE(HTMLe)@en[[[script]]]]
で他のホストに[[要求]]を送らせること自体は既にできるので、新たな脅威ではなさそうです。

;; [39] ただし [[CORS]] なしで [[JSON]] を異なる[[起源]]に [CODE(HTTP)@en[[[POST]]]]
できるのは初めてと思われます。
これを想定していない [[Webアプリケーション]]はあるかもしれません。

[43] [[利用者エージェント]]は同じ[[起源]]に制限しても構いません [SRC[>>42]]。

;; [44] [[PKP-RO]] の場合は良いとして、 [[PKP]] の場合はほぼ確実に送れなくなりますが...

[5] [[利用者エージェント]]は、指定された [[URL]] に報告を [CODE(HTTP)[[[POST]]]]
します [SRC[>>1, >>22]]。

;; [24] [[RFC]] では、「POST」と書かれているだけで、その意味はなぜか明記されていません。
[[要求メソッド]] [CODE(HTTP)@en[[[POST]]]] により送信することを意味すると推測されます。

[7] [[利用者エージェント]]は、指定された [[URL scheme]] が [[TLS]]
を使うものなら、[[ホスト]]が [[Known Pinned Host]] であるなら [[Pinning Validation]] 
をしなければ[['''なりません''']] [SRC[>>1]]。

[8] [[利用者エージェント]]は、指定された[[ホスト]]が[[既知HSTSホスト]]なら、
[[HSTS]] を適用しなければ[['''なりません''']] [SRC[>>1]]。

;; [9] [[リダイレクト]]をどう処理するべきかは不明です。

;; [10] 趣旨からすると [[HSTS]] 適用後に [[TLS]] を使うなら [[Pin Validation]]
を行うべきと思われます (が仕様書にはそうは書いていません)。

[13] 報告先ホストが [[Pin Validation]] に失敗し、元のホストに報告するよう求めるようなループを検出し、報告をやめる[['''べき''']]です [SRC[>>1]]。

;; [14] なぜこれが MUST でなくて SHOULD なのかは謎です。無限ループに陥る実装が正当である理由など無いと思うのですが...

[15] 報告失敗時には、後から再送を試みても構いません [SRC[>>1]]。

[16] 報告送信頻度は制限する[['''べきです''']] [SRC[>>1]]。
同じ報告をむやみに繰り返さないよう努力する[['''べきです''']] [SRC[>>20]]。

[EG[
[17] 例えば同じ組の [[Pin]] に関して同じ [[URL]] に同じ報告を何度も送る必要はありません
[SRC[>>1]]。
]EG]

;; [21] [[PKP-RO]] は当該[[応答]]の処理後は検証のために情報を保持しないことになってはいますが、
報告の重複チェックのために保持することは禁止されていない (むしろ求められている)
ようです。

[23] [[POST]] するデータは、次のような [[JSONオブジェクト]]です [SRC[>>22]]。
[FIG(list members)[
[FIGCAPTION[
[[JSONオブジェクト]]
]FIGCAPTION]
:[CODE[[[date-time]]]]:
[[Pin Validation]] に失敗した時刻を、 [[RFC 3339の日時形式]]で表したものです [SRC[>>22]]。
:[CODE[[[hostname]]]]:
[[Pin Validation]] に失敗した[[要求]]の[[ホスト名]]を表す[[文字列]]です [SRC[>>22]]。
:[CODE[[[port]]]]:
[[Pin Validation]] に失敗した[[要求]]の[[ポート]]を表す[[整数]]です [SRC[>>22]]。
:[CODE[[[effective-expiration-date]]]]:
[[ピン]]の[[実効満期日付]]を、 [[RFC 3339の日時形式]]で表したものです [SRC[>>22]]。
:[CODE[[[include-subdomains]]]]:
[CODE[[[includeSubDomains]]]] [[指令]]が指定されていたかどうかを [[boolean]]
で表したものです [SRC[>>22]]。
:[CODE[[[noted-hostname]]]]:
[[既知ピン付きホスト]]として記録された時の[[ホスト名]]です [SRC[>>22]]。
[CODE[[[includeSubDomains]]]] が指定されていた時は [CODE[[[hostname]]]]
と異なる値になるかもしれません。
:[CODE[[[served-certificate-chain]]]]:
[[TLSセッション]]の設定の時点で[[サーバー]]から提供された[[証明書鎖]]を、
各 [[X.509証明書]]の [[.pem]] 形式の文字列の[[配列]]としたものです [SRC[>>22]]。
:[CODE[[[validated-certificate-chain]]]]:
[[証明書鎖]]の[RUBYB[検証]@en[verification]]の過程で[[利用者エージェント]]が構築した[[証明書鎖]]を、
各 [[X.509証明書]]の [[.pem]] 形式の文字列の[[配列]]としたものです [SRC[>>22]]。
検証の過程で複数組の[[証明書鎖]]を構築した場合は、最後のものとする[['''べきです''']] [SRC[>>22]]。
:[CODE[[[known-pins]]]]:
[[既知ピン付きホスト]]に関して記録されている[[ピン]]の[[配列]]です。
各[[ピン]]は、[[ハッシュアルゴリズム]]名、
[CODE[[[=]]]]、[[引用文字列]]の形にした[[文字列]]です。[[引用文字列]]は、
[[SPKI Fingerprint]] を [[base64]] 符号化したものです。 [SRC[>>22]]
]FIG]

[25] 同じ名前と値の組が複数あっては[['''なりません''']] [SRC[>>22]]。

[33] (広義の) [[HTTP]] の一部であるにも関わらず、[[HTTPの日時形式]]ではなく
[[RFC 3339の日時形式]]が採用されています。

;; [[JSON]] ではしばしば [[RFC 3339の日時形式]]等 [[ISO 8601の日時形式]]のバリエーションが使われるためでしょうか。

[27] [[証明書鎖]]は、含まれる[[証明書]]の順序をそのまま[[配列]]内の[[文字列]]の順序とするべきと思われます。
(自明と考えられたためか、明記されていません。)

[45] [[証明書鎖]]には、組織内で使う [[MITM proxy]] の[[証明書]]のような、
外部に晒したくない情報が含まれてしまう場合もあり、注意が必要です
[SRC[>>42]]。

;; [46] どう対処するべきなのかは不明です。

[28] [CODE[[[known-pins]]]] の各[[ピン]]の値は、 [CODE[[[pin-*]]]]
[[指令]]と同じ構文となっています。
値は[[引用文字列]]でなければならず、[[字句]]ではいけないようです。

[29] [[アルゴリズム]]の名前は、[CODE[[[pin-*]]]] [[指令]]の名前と同じものとされていることから、
[[大文字・小文字不区別]]と思われますが、明記はされていません。

[30] [[RFC]] は[[引用文字列]]に [CODE["]] が含まれることからその [[JSON]]
[[文字列]]では [CODE[\]] により[[エスケープ]]するか、 [CODE[']]
で括るかのいずれかとしなければ[['''ならない''']]としています。例 (>>26)
も [CODE[']] を使っています。しかし、 [[JSON]] では [CODE[']]
で文字列を括ることは認められていませんから、本 [[RFC]] と [[JSON]]
の両方の規定を満たすためには、 [CODE[']] は使えませんし、 [[RFC]]
の例は正しくありません。[[RFC正誤表]]はこれを修正しています [SRC[>>31]]。

;; [32] 本 [[RFC]] は[[提案標準]]であり、[[IESG]] の承認を含め多くの人の目を経て出版されているはずですが、
このような初歩的かつ致命的な誤りが含まれたまま [[RFC]] として出版されるとは、
[[IETF]] の手続きは何とも杜撰なもののようです。

[EG[
[26] 例えば次のようにします [SRC[>>22, >>31]]。

[PRE(JSON code)[
  {
    "date-time": "2014-04-06T13:00:50Z",
    "hostname": "www.example.com",
    "port": 443,
    "effective-expiration-date": "2014-05-01T12:40:50Z"
    "include-subdomains": false,
    "served-certificate-chain": [
      "-----BEGIN CERTIFICATE-----\nMIIEBDCC...kVDNx\n-----END CERTIFICATE-----",
      ...
    ],
    "validated-certificate-chain": [
      "-----BEGIN CERTIFICATE-----\nMIIEBDCI...kVDNx\n-----END CERTIFICATE-----",
      ...
    ],
    "known-pins": [
      "pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\"",
      "pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\""
    ]
  }
]PRE]
]EG]

[38] 報告は [[JSON]] なので、 [[MIME型]] ([CODE(HTTP)@en[[[Content-Type:]]]] [[ヘッダー]])
を [CODE(MIME)@en[[[application/json]]]] としなければならないものと推測されますが、
[[RFC]] には明記されていません。

[40] [CODE(HTTP)@en[[[Referer:]]]], [CODE(HTTP)@en[[[Origin:]]]],
[CODE(HTTP)@en[[[Cookie:]]]], [CODE(HTTP)@en[[[Accept-Language:]]]]
その他の[[ヘッダー]]をどう扱うべきかは不明です。

[41] [[Service Worker]] を通すべきかどうかは不明です。

* メモ

[47] [CITE@en[Deprecate 'report-uri'. Drop 'reports'. 'report-to' is the new hotness. · w3c/webappsec-csp@90528dd]]
([TIME[2015-12-07 15:40:44 +09:00]] 版)
<https://github.com/w3c/webappsec-csp/commit/90528ddb877c8241208f83e752a2f4cf6829e610>

[48] [CITE@en['report-to' overrides 'report-uri'. Closes #51. · w3c/webappsec-csp@ab03aef]]
([TIME[2016-01-13 12:11:20 +09:00]] 版)
<https://github.com/w3c/webappsec-csp/commit/ab03aef0560b244f90b310d39db04e29c3cdc29f>

[49] [CITE@en[No CSP report-uri|frame-ancestors|sandbox in meta · whatwg/html@3947072]]
([TIME[2016-01-30 20:56:07 +09:00]] 版)
<https://github.com/whatwg/html/commit/39470724136a366bab4e893efd889a513d61cc3e>

[50] [CITE@en[Pass a base URL to the URL parser for violation reporting.]]
([[mikewest]]著, [TIME[2016-12-02 23:00:36 +09:00]])
<https://github.com/w3c/webappsec-csp/commit/5e4ef7a41c44a7229db10d33659a980f04494f00>

[51] [CITE@en[Exclude fragments from reported URLs.]]
([[mikewest]]著, [TIME[2017-03-17 22:17:36 +09:00]])
<https://github.com/w3c/webappsec-csp/commit/c60db267c4f295d50652a6ca24d825059f83390e>

[52] [CITE@en[Note that violation reports are attacker controlled.]]
([[mikewest]]著, [TIME[2017-03-23 22:53:05 +09:00]])
<https://github.com/w3c/webappsec-csp/commit/6b9fdc97d9a8acfe00b62f5000d83f55ee13b5e6>