| 互联网工程任务组 (IETF) | M. Nottingham |
| 请求评议:9211 | Fastly |
| 类别:标准轨道 | 2022年6月 |
| ISSN: 2070-1721 |
Cache-Status HTTP 响应头字段
摘要
为了帮助调试,HTTP 缓存通常会在响应中附加一些头字段,以说明它们如何以临时方式处理请求。本规范定义了一种与 HTTP 缓存模型一致的标准机制来实现此目的。
本备忘录的状态
这是一个互联网标准轨道文档。
本文件是互联网工程任务组(IETF)的成果,代表 IETF 社区的共识。它已获得公开评审,并由互联网工程指导小组(IESG)批准发布。关于互联网标准的更多信息请参见 RFC 7841 第2节。
关于本文档当前状态、勘误及如何反馈信息,可访问 https://www.rfc-editor.org/info/rfc9211 获取。
Copyright Notice
Copyright (c) 2022 IETF Trust and the persons identified as the document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.
1. 引言
为了便于调试(无论是人工还是自动化工具),HTTP 缓存经常在响应中追加头字段,以说明它们如何处理该请求。不幸的是,这些头字段的语义通常不明确,且不同实现之间在语义和语法上各不相同。
本规范为此目的定义了一个新的 HTTP 响应头字段 "Cache-Status",并为其提供了标准化的语法与语义。
1.1. 符号约定
文中关键词 "MUST"、"MUST NOT"、"REQUIRED"、"SHALL"、"SHALL NOT"、"SHOULD"、"SHOULD NOT"、"RECOMMENDED"、"NOT RECOMMENDED"、"MAY" 和 "OPTIONAL" 的解释应参照 BCP 14 中的说明,详见 [RFC2119] 和 [RFC8174],仅在这些词以全大写形式出现时适用。
本文件使用 Section 3 中的术语来指定语法与解析(来自 STRUCTURED-FIELDS):List、String、Token、Integer 和 Boolean。
本文件还使用来自 [HTTP] 与 [HTTP-CACHING] 的术语。
2. Cache-Status HTTP 响应头字段
Cache-Status HTTP 响应头字段用于指示缓存如何处理该响应及其对应的请求。该头字段的语法符合 [STRUCTURED-FIELDS] 的规定。
其值是一个 List。列表的每个成员表示处理过该请求的一个缓存。第一个成员表示最接近源服务器的缓存,最后一个成员表示最接近用户的缓存(如果用户代理自身追加了值,则可能包括用户代理的缓存)。
缓存决定何时在响应中添加 Cache-Status 头字段。有些缓存可能会对所有响应添加该字段,而另一些仅在特定配置或请求包含激活调试模式的头字段时添加。有关相关安全注意事项,请参见 第 6 节。
中间件 SHOULD NOT 向其本地生成的响应追加 Cache-Status 成员,即使该中间件包含缓存,也不应追加,除非该生成的响应是基于已存储响应(例如 304 (Not Modified) 和 206 (Partial Content) 都基于已存储的响应)。例如,代理因请求格式错误生成 400 响应时不会添加 Cache-Status,因为该响应是代理生成的,而非源服务器生成的。
在向 Cache-Status 头字段添加值时,缓存 SHOULD 保留已存在的字段值,以便调试处理该请求的整个缓存链。
列表的每个成员都要标识插入该成员的缓存,该标识 MUST 是一个 String 或 Token。根据部署情况,这可以是产品或服务名称(例如 "ExampleCache" 或 "Example CDN")、主机名("cache-3.example.com")、IP 地址或生成的字符串。
列表的每个成员可以包含描述该缓存如何处理请求的参数。尽管这些参数为 OPTIONAL,但鼓励缓存尽可能提供更多信息。
本规范定义了以下参数。
2.1. hit 参数
"hit" 的值为 Boolean,当其为 true 时表示该请求由缓存满足;也就是说,请求未被转发,响应来自缓存。
如果响应最初由源站生成但被缓存修改(例如 304 或 206 状态码),只要没有向前转发(例如用于验证),仍然被视为 hit。
如果响应在缓存中但在使用前必须向前转发(例如因为已陈旧或为部分内容),则不被视为 hit。注意,当在未向前转发的情况下使用已陈旧的响应(例如源站不可用)时,可以将其视为 hit。
"hit" 与 "fwd" 互斥;每个列表成员上只应出现其中之一。
2.2. fwd 参数
当存在 "fwd" 时,表示请求已被转发到源站;其值为一个 Token,用来说明转发的原因。
下列参数值用于解释请求为何被转发,按从最具体到最不具体排序:
- bypass:
- 缓存被配置为不处理此请求。
- method:
- 请求方法的语义要求将请求转发。
- uri-miss:
- 缓存中没有与请求 URI 匹配的任何响应。
- vary-miss:
- 缓存中存在与请求 URI 匹配的响应,但无法基于本次请求的头字段和已存的 Vary 首部来选择合适的响应。
- miss:
- 缓存中没有任何可以用于满足该请求的响应(供无法区分 uri-miss 与 vary-miss 的实现使用)。
- request:
- 缓存能够为请求选择一个新鲜的响应,但请求的语义(例如 Cache-Control 请求指令)不允许使用它。
- stale:
- 缓存能够为请求选择一个响应,但该响应已陈旧。
- partial:
- 缓存能够选择部分响应,但并未包含请求的所有范围(或请求为完整响应)。
应尽可能使用缓存已知的最具体原因(SHOULD)。另见 [HTTP-CACHING],以及 RFC 9111 第 4 节。
2.3. fwd-status 参数
"fwd-status" 的值为 Integer,表示下一跳服务器对转发请求返回的状态码(见 [HTTP],第 15 节)。仅当存在 fwd 时该参数才有意义。如果 fwd 存在但未提供 fwd-status,则默认使用响应中发送的状态码。
该参数有助于区分下一跳服务器对条件请求返回 304 (Not Modified) 或因范围请求返回 206 (Partial Content) 的情形。
2.4. ttl 参数
"ttl" 的值为 Integer,表示缓存计算的响应剩余新鲜期(见 [HTTP-CACHING],第 4.2.1 节),以秒为单位,并尽可能接近缓存发送响应头时测量。该值包含缓存通过启发式方法(见 [HTTP-CACHING],第 4.2.2 节)、本地配置或其他因素分配的有效期。该值可以为负,以表示响应已陈旧。
2.5. stored 参数
"stored" 的值为 Boolean,表示缓存是否已存储该响应(见 [HTTP-CACHING],第 3 节);值为 true 表示已存储。仅当存在 fwd 时该参数才有意义。
2.6. collapsed 参数
"collapsed" 的值为 Boolean,指示该请求是否与一个或多个其他转发请求合并(见 [HTTP-CACHING],第 4 节)。若为 true,表示响应已被成功复用;若为 false,表示必须发起新的请求。若该参数不存在,则表示请求未与其他请求合并。仅当存在 fwd 时该参数才有意义。
2.7. key 参数
"key" 的值为 String,传达用于该响应的缓存键的表示(见 [HTTP-CACHING],第 2 节)。注意该值可能与实现相关。
2.8. detail 参数
"detail" 的值为 String 或 Token,允许实现传递其他参数未涵盖的补充信息,例如实现特定的状态或其他与缓存相关的度量。
例如:
Cache-Status: ExampleCache; hit; detail=MEMORY
detail 参数的语义始终特定于发送该参数的缓存;即使来自另一个缓存的 detail 参数具有相同的值,也可能并不具有相同含义。
该参数的设计有意受限。如果实现的开发者或运营者需要以可互操作的方式传递额外信息,建议注册扩展参数(见 第 4 节)或定义另一个头字段。
3. 示例
下面是一个最小的缓存命中示例:
Cache-Status: ExampleCache; hit
不过,更礼貌的缓存会提供更多信息,例如:
Cache-Status: ExampleCache; hit; ttl=376
已陈旧的命中只是具有负的新鲜度,例如:
Cache-Status: ExampleCache; hit; ttl=-412
而下面是一个完全未命中的示例:
Cache-Status: ExampleCache; fwd=uri-miss
这是一个在后端服务器上成功验证的未命中示例:
Cache-Status: ExampleCache; fwd=stale; fwd-status=304
这是一个与其他请求合并(collapsed)的未命中示例:
Cache-Status: ExampleCache; fwd=uri-miss; collapsed
这是一个缓存尝试合并但未能合并的示例:
Cache-Status: ExampleCache; fwd=uri-miss; collapsed=?0
下面示例展示经过两层独立缓存的情况:最接近源的缓存对早先的请求以已存储的响应作出回应;第二层缓存存储了该响应并在后续请求中重用它以满足当前请求:
Cache-Status: OriginCache; hit; ttl=1100,
"CDN Company Here"; hit; ttl=545
下面示例展示三层缓存系统:最接近源的是反向代理(在此处响应来自缓存);其次是网络中插入的正向代理(由于其缓存中没有与 URI 匹配的响应,请求被转发,并与其他请求合并,随后存储了结果响应);最接近用户的是浏览器缓存(其缓存中没有与请求 URI 匹配的响应):
Cache-Status: ReverseProxyCache; hit Cache-Status: ForwardProxyCache; fwd=uri-miss; collapsed; stored Cache-Status: BrowserCache; fwd=uri-miss
4. 定义新的 Cache-Status 参数
可以通过在 "HTTP Cache-Status" 注册表中注册来定义新的 Cache-Status 参数。
专家在评估请求时应考虑下列因素:
- 社区反馈
- 该值是否定义得足够明确
- 优先采用通用参数,而非供应商、应用或部署特定的值。如果社区无法达成通用值的共识,则参数名称应相应地具体(例如以能够识别供应商、应用或部署的前缀命名)。
注册请求应使用下列模板:
- Name:
- [Cache-Status 参数键的名称;参见 Section 3.1.2 中关于 [STRUCTURED-FIELDS] 的语法要求]
- Type:
- [参数值的 Structured Type;参见 Section 3.1.2 中关于 [STRUCTURED-FIELDS] 的说明]
- Description:
- [参数语义的描述]
- Reference:
- [若有,引用定义该参数的规范]
有关将注册请求发送到何处的详细信息,请参见注册表 <https://www.iana.org/assignments/http-cache-status>。
5. IANA 注意事项
IANA 已创建 "HTTP Cache-Status" 注册表,地址为 <https://www.iana.org/assignments/http-cache-status>,并将第 2 节 中定义的类型填入其中;其关联程序见 第 4 节。
- Field name:
- Cache-Status
- Status:
- permanent
- Reference:
- RFC 9211
6. 安全性注意事项
攻击者可以利用 Cache-Status 中的信息探测缓存(及其他组件)的行为,从而推断使用该缓存的活动。Cache-Status 头字段本身可能并不会直接产生这些风险,但它可以帮助攻击者更容易地利用这些风险。
例如,知道缓存是否存储了某个响应可能帮助攻击者对敏感数据执行计时攻击。
此外,暴露缓存键(cache key)可能帮助攻击者了解对缓存键的修改,从而助长缓存投毒攻击。详情参见 [ENTANGLE]。
可以通过多种技术来缓解这些基础风险(例如使用加密与认证,避免在缓存键中包含攻击者可控的数据等),具体方法取决于风险的性质。注意,仅对键进行混淆并不能缓解此类风险。
为避免协助此类攻击,可以省略 Cache-Status 头字段,仅在客户端被授权接收时发送,或仅在客户端被授权时才发送包含敏感信息(例如 key 参数)的字段。
7. 参考文献
7.1. 规范性引用
- [HTTP]
- Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., “HTTP Semantics”, STD 97, RFC 9110, DOI 10.17487/RFC9110, 2022 年 6 月,<https://www.rfc-editor.org/info/rfc9110>.
- [HTTP-CACHING]
- Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., “HTTP Caching”, STD 98, RFC 9111, DOI 10.17487/RFC9111, 2022 年 6 月,<https://www.rfc-editor.org/info/rfc9111>.
- [RFC2119]
- Bradner, S., “Key words for use in RFCs to Indicate Requirement Levels”, BCP 14, RFC 2119, DOI 10.17487/RFC2119, 1997 年 3 月,<https://www.rfc-editor.org/info/rfc2119>.
- [RFC8126]
- Cotton, M., Leiba, B., and T. Narten, “Guidelines for Writing an IANA Considerations Section in RFCs”, BCP 26, RFC 8126, DOI 10.17487/RFC8126, 2017 年 6 月,<https://www.rfc-editor.org/info/rfc8126>.
- [RFC8174]
- Leiba, B., “Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words”, BCP 14, RFC 8174, DOI 10.17487/RFC8174, 2017 年 5 月,<https://www.rfc-editor.org/info/rfc8174>.
- [STRUCTURED-FIELDS]
- Nottingham, M. and P-H. Kamp, “Structured Field Values for HTTP”, RFC 8941, DOI 10.17487/RFC8941, 2021 年 2 月,<https://www.rfc-editor.org/info/rfc8941>.
7.2. 补充性引用
- [ENTANGLE]
- Kettle, J., “Web Cache Entanglement: Novel Pathways to Poisoning”, 2020 年 9 月,<https://portswigger.net/research/web-cache-entanglement>.