摘要

  • RFC 10025 有意为 Cookie 生产方和消费方规定不同的行为边界。格式正确的 Set-Cookie 仍可能被用户代理忽略、拒绝、规范化、替换,或者在下一次请求前被清除。
  • “已经存储”不等于“这次应当发送”,“已经发送”也不等于“应用已经授权”。可问责的控制需要串联各层判定,同时避免把 Cookie 值与会话秘密写入日志。

设想一个没有具体厂商背景的场景。认证服务返回预期状态码,并发出两行彼此独立的 Set-Cookie。上线检查抓到了原始响应,于是把“建立会话”标成完成。随后,一组请求没有携带 Cookie,另一组请求却带来了两个同名值。

单凭这些现象,不能断言网络丢包,也不能断言浏览器违约。用户代理可能因前缀条件不成立而拒绝指令,可能按本地策略屏蔽它,也可能接纳后用同名、同域、同路径的新条目替换旧条目。条目还可能到期、在配额竞争中被逐出,或者只是不符合下一次请求的域、路径、安全通道与同站条件。

RFC 10025 正是这条边界的权威来源。它是 2026 年 7 月发布的 IETF 标准轨道文件,取代 RFC 6265,定义 Cookie 与 Set-Cookie 字段。服务器在响应中发送名称、值和属性;用户代理后来只在适用时随请求带回所选名称和值。两者不是一对对称的发送与签收报文。

生产方的克制与消费方的兼容

RFC 10025 要求实现者先判断自己属于哪一类。生产 Cookie 的服务应限制在较严格、行为良好的格式内;消费 Cookie 的用户代理则必须容忍现实中更宽的服务器行为。前者减少歧义,后者维护兼容性。它们共同规定互操作,却没有共同签署“双方得到同一状态”。

因此,服务端校验器最多证明“发出的指令符合生产方规范”。它不知道消费引擎的版本、本地策略、响应发生时的上下文,更不知道存储算法走过哪条分支。该算法在开始处就允许用户代理整项忽略收到的 Cookie。“收到”在这里是处理输入,不是接纳结论。

治理问题由此显现:应用团队控制响应,HTTP 栈控制字段运输,用户代理控制解析与存储,用户或设备管理员可能控制策略,导航、嵌套文档、worker 或非 HTTP API 又决定下一次取用上下文,最后才轮到业务服务判定会话与权限。一个“Cookie 成功”灯无法替这些主体同时作证。

接纳过程会重建一条本地记录

用户代理不是照抄字符串。名称和值含有被禁止的控制字符、二者总长度超限、Domain 不可接受,或者属性组合不满足条件时,算法会中止并拒绝新条目。SameSite=None 却没有 Secure 的 Cookie 不会被接纳。__Secure- 与 __Host- 前缀只有在相应安全条件成立时才获得意义;消费方还要以不区分大小写的方式识别这些前缀,防止服务器自身的大小写处理制造错误保证。

被接纳的对象包含名称、值、实际到期时间、域、路径、创建时间、最近访问时间,以及持久、仅主机、安全、HttpOnly、SameSite 等标志。Max-Age 优先于 Expires。没有 Domain 时形成仅主机范围。替换关系不是只看名称,而是同时比较名称、域与路径;替换时还涉及创建时间的继承。

所以,原始响应头与最终存储行并不是同一证据。诊断若只有“服务端发了”和“后来没见到”,就无法区分语法拒绝、隐私策略、范围错误、合法替换与旧状态仍在。需要记录的是不含秘密的指令指纹、接纳结果、拒绝类别和规范化后的范围。

到期时间只是上限,不是保管承诺

服务器可以提出最大寿命,却不能在用户代理中预订存储空间。用户代理可以调整实际到期时间,按自己的年龄上限截断,清除已到期条目,在总量或同域数量超限时逐出其他条目。用户也可以主动删除,策略可以缩短保留,而非持久 Cookie 会在用户代理自行定义的会话结束时被清除。

因此,“一年后到期”不能证明一年内仍在。若提前消失,真正有用的事实是保留事件:何时、哪一条不透明记录、因到期、替换、用户删除、会话结束、配额还是策略清理而退出。

但可观测性不能越权。受管终端可以在本地留下细粒度审计;公共网站没有理由索取访问者的完整 Cookie 仓库。跨边界数据应使用粗粒度原因、汇总比例或用户明确同意的诊断,绝不能为排障集中 Cookie 值、Bearer 令牌或无关浏览历史。

每一次取用都重新计算

存储行存在,不代表它必然进入下一次请求。RFC 10025 的取用模型要结合具体 URI、同站状态与取用类型。到期、主机或域不匹配、路径不匹配、通道不安全、HttpOnly 限制与 SameSite 规则都能排除条目。用户代理还可以依据 Cookie 策略完全省略 Cookie 字段。

WHATWG Fetch 把 Cookie 纳入 Web 请求的凭据处理。HTML 的 document.cookie 则属于非 HTTP API,不具备访问 HttpOnly 状态的权力。顶层导航、嵌套文档、刷新、共享 worker 与 service worker 的“Cookie 所属站点”并不都按同一路径计算。只记录目标 URL 无法复现当时的选择。

SameSite 最能说明“属性不是授权”。Strict、Lax、None 与 Default 要在具体导航和文档上下文中生效;兼容模式甚至可以在用户代理选择的短时间窗口内,对近期 Default 条目放宽不安全方法的顶层导航。RFC 把 SameSite 定位为纵深防御,而不是通用 CSRF 解法,并明确指出属性由服务器设置,不代表用户亲自作出决定。

回传名称和值,不回传履历

请求中的 Cookie 通常只包含名称和值,不包含 Domain、Path、SameSite、创建时间或本次为何入选。同一名称可以因域或路径不同而存在多条记录,服务端不应把序列化顺序当成业务优先级。RFC 9113 与 RFC 9114 还允许 HTTP/2 或 HTTP/3 将一条逻辑 Cookie 字符串分布在多行字段中;运输形态不会补回存储履历。

应用收到后仍要解析、查询会话、检查轮换或撤销、认证主体,再判断该主体是否有权以这个方法操作这项资源。RFC 9110 提供 HTTP 语义,但业务授权不由 Cookie 属性代办。

RFC 10025 将 Cookie 描述为一种环境权力。第三方可能诱导用户代理发出请求,即使第三方并不知道 Cookie 值,用户代理仍会自动附上它。因而,Cookie 出现不等于用户有此操作意图;Cookie 缺失也不等于用户表达了隐私偏好。两者都必须回到实际状态迁移与请求来源来判断。

六段式生命周期回执

第一段记录发出:响应 URL、时间、未经错误合并的有序 Set-Cookie 行、发布与配置身份,以及隐藏值的指纹。第二段记录接纳:消费引擎、有效策略版本、解析结论、拒绝类别与被接纳指令的指纹。第三段记录存储:规范化范围、标志、实际到期时间、替换对象与创建时间处理。

第四段是保留事件,在有合法可见性时记录到期、删除、会话结束、替换或逐出。第五段把一次请求与 URI、方法、发起者、顶层上下文、SameSite 计算和入选或被拦的条目 ID 绑定。第六段由应用分别记录解析、会话查询、认证、CSRF 控制、授权和最终结果。

这是 Daniel Kade 提出的治理模型,不是 RFC 10025 规定的遥测格式,也不是要求浏览器公开私有仓库。它只让每一方说一条自己能证明的窄结论。

这种做法遵循 Heng Lu 对运行代码作为第一证据的强调。政策镜像应呈现谁在何时作出了哪项决定,而不是把服务器的愿望写成客户端事实。只有坚持现实而非倡议,故障、拒绝与授权才能落到真正负责的边界。

来源