跳到主要内容

3. 报告 Expect-CT 失败 (Reporting Expect-CT Failure)

当 UA 尝试连接到 Known Expect-CT Host 且该连接不满足 CT qualified 条件时, 如果 Known Expect-CT Host 的 Expect-CT 元数据中存在 report-uri, UA SHOULD 向该 report-uri 报告 Expect-CT 失败.

当 UA 通过不满足 CT qualified 条件的连接收到 Expect-CT 响应头字段时, 如果 UA 尚未针对该连接发送 Expect-CT 报告, 则如果配置了 report-uri, UA SHOULD 向该 report-uri 报告 Expect-CT 失败.

3.1. 生成违规报告

为了生成违规报告对象, UA 构造一个 JSON [RFC8259] 对象, 其中包含以下键和值:

"date-time"

该键的值表示 UA 观察到 CT 合规性失败的 UTC 时间. 该值是一个字符串, 按照 [RFC3339] 第 5.6 节 "Internet Date/Time Format" 进行格式化.

"hostname"

该值是 UA 发起原始请求时使用的 hostname, 该请求未通过 CT 合规性检查. 该值以字符串形式提供.

"port"

该值是 UA 发起原始请求时连接的端口, 该请求未通过 CT 合规性检查. 该值以整数形式提供.

"scheme"

(可选) 该值是 UA 发起原始请求时使用的 scheme, 该请求未通过 CT 合规性检查. 该值以字符串形式提供. 该键是可选的, 如果不存在, 则假定为 "https".

"effective-expiration-date"

该值表示未通过 CT 合规性检查的 Expect-CT Host 的 Effective Expiration Date (见第 2.3.2.2 节), 使用 UTC 时间. 该值以字符串形式提供, 按照 [RFC3339] 第 5.6 节 "Internet Date/Time Format" 进行格式化.

"served-certificate-chain"

该值是在 TLS 会话建立期间由 Expect-CT Host 提供的证书链. 该值以字符串数组形式提供, 证书出现顺序MUST与服务器提供它们的顺序一致. 数组中的每个字符串都是 [RFC7468] 所描述的每个 X.509 证书的 Privacy-Enhanced Mail (PEM) 表示.

"validated-certificate-chain"

该值是 UA 在证书链验证期间构造的证书链. 这可能不同于 "served-certificate-chain" 键的值. 该值以字符串数组形式提供, 证书出现顺序MUST与 UA 验证的链相匹配. 数组中的每个字符串都是 [RFC7468] 所描述的每个 X.509 证书的 PEM 表示. 链中的第一个证书表示正在验证的终端实体证书. 在验证过程中以多种方式构建证书链的 UA SHOULD 发送最后构建的链.

"scts"

该值表示 UA 为 Expect-CT Host 收到的 SCT, 如果有的话, 以及它们的验证状态. 该值以 JSON 对象数组形式提供. SCT 可以按任意顺序出现. 数组中的每个 JSON 对象具有以下键:

  • "version" 键, 其值为整数. 如果 SCT 采用 [RFC6962] 第 3.2 节定义的格式, UA MUST 将该值设置为 1. 如果 SCT 采用 [RFC9162] 第 4.5 节定义的格式, UA MUST 将该值设置为 2.

  • "status" 键, 其值为字符串, UA MUST 将其设置为以下值之一: "unknown", 表示 UA 没有或不信任签发该 SCT 的日志的公钥; "valid", 表示 UA 已按照 [RFC6962] 第 5.2 节或 [RFC9162] 第 8.1.3 节成功验证 SCT; 或 "invalid", 表示 SCT 验证由于签名错误或时间戳无效而失败.

  • "source" 键, 其值为字符串, 指示 UA 从何处获得 SCT, 其定义见 [RFC6962] 第 3 节和 [RFC9162] 第 6 节. UA MUST 将该值设置为以下值之一: "tls-extension", "ocsp", 或 "embedded". 这些值对应 [RFC6962] 第 3.3 节描述的在 TLS 握手中传递 SCT 的三种方法.

  • "serialized_sct" 键, 其值为字符串. 如果 "version" 键的值为 1, UA MUST 将该值设置为 [RFC6962] 第 3.2 节中序列化 SignedCertificateTimestamp 结构的 base64 编码 [RFC4648]. base64 编码在 [RFC4648] 第 4 节中定义. 如果 "version" 键的值为 2, UA MUST 将该值设置为代表 SCT 的序列化 TransItem 结构的 base64 编码 [RFC4648], 该结构见 [RFC9162] 第 4.5 节.

"failure-mode"

该值指示 Expect-CT 报告是由 enforce 模式还是 report-only 模式下的 Expect-CT 策略触发的. 该值以字符串形式提供. 如果 Expect-CT 元数据指示 enforce 配置, UA MUST 将该值设置为 "enforce", 否则设置为 "report-only".

"test-report"

(可选) 如果该报告由测试客户端发送, 用于验证报告服务器行为是否正确, 则该值设置为 true. 该值以 boolean 形式提供. 如果报告用于测试服务器行为并且可以丢弃, 则该值MUST设置为 true.

3.2. 发送违规报告

UA SHOULD 为 Known Expect-CT Hosts 报告 Expect-CT 失败. 也就是说, 当连接到 Known Expect-CT Host 的连接不符合 UA 的 CT Policy, 且该主机的 Expect-CT 元数据包含 report-uri 时, UA SHOULD 发送报告.

此外, 对于没有任何已存储 Expect-CT 元数据的主机, UA SHOULD 报告 Expect-CT 失败. 也就是说, 当 UA 连接到某个主机并收到包含 report-uri 指令的 Expect-CT 头字段时, 如果连接不符合 UA 的 CT Policy, UA SHOULD 报告 Expect-CT 失败.

报告 Expect-CT 失败的步骤如下.

  1. 准备一个 JSON 对象 report object, 其中只有一个键 "expect-ct-report", 其值为按照第 3.1 节生成的违规报告对象.

  2. 令 report body 为 report object 的 JSON 字符串化结果.

  3. 令 report-uri 为 Expect-CT 头字段中 report-uri 指令的值.

  4. 向 report-uri 发送 HTTP POST 请求, 其 Content-Type 头字段为 application/expect-ct-report+json, 实体主体由 report body 组成.

UA MAY 在发送 HTTP POST 请求时执行其他操作, 例如作为 [FETCH] 的一部分发送 Cross-Origin Resource Sharing (CORS) 预检请求.

本规范的未来版本可能需要修改或扩展 Expect-CT 报告格式. 它们可以通过定义新的顶层键来包含报告, 从而替换 "expect-ct-report" 键. 第 3.3 节定义报告服务器应如何处理其不支持的报告格式.

3.3. 接收违规报告

收到 Expect-CT 违规报告后, 如果报告服务器能够将请求主体解析为有效 JSON, 报告符合第 3.1 节描述的格式, 并且它识别报告中 "scheme", "hostname" 和 "port" 字段里的 scheme, hostname 和 port, 则报告服务器MUST以 2xx (Successful) 状态码响应. 如果报告主体无法解析, 或者不符合第 3.1 节描述的格式, 或者报告服务器不期望接收该报告中 scheme, hostname 或 port 对应的报告, 则报告服务器MUST以 400 Bad Request 状态码响应.

如第 3.2 节所述, 本规范的未来版本可能定义使用不同顶层键发送的新报告格式. 如果报告服务器无法识别该报告格式, 则报告服务器MUST以 501 Not Implemented 状态码响应.

如果报告的 "test-report" 键设置为 true, 服务器MAY丢弃该报告而不做进一步处理, 但仍然MUST返回 2xx (Successful) 状态码. 如果 "test-report" 键不存在或设置为 false, 服务器SHOULD存储该报告, 供 Expect-CT Host 的所有者处理和分析.