摘要

  • DNS Cookies 给 UDP DNS 增加一种轻量、服务端无须保存逐客户端状态的信号。有效 Server Cookie 只是把一次先前往返与 Client Cookie、源 IP 弱绑定;它不识别人或机构,不认证 DNS 数据,不隐藏查询,也挡不住 on-path 观察者。
  • RFC 9018 规定 version 1 使用 16 字节 Server Cookie、SipHash-2-4、时间戳和可配置 Server Secret。anycast 各节点必须识别相同密钥 epoch,因而秘密分发与轮换本身就是执行权边界。
  • 审计必须从 COOKIE 原始字节一直连到验证原因、节点、epoch、BADCOOKIE、实际放宽了哪项防御、响应大小与重试结果。“valid”只是结论,不是证据链。

系统说“见过”,到底见过谁

设想一组 authoritative DNS anycast 节点突然收到大量 UDP 查询,请求的又是较大的签名响应。对第一次出现的源地址,服务采取保守策略,避免把伪造请求放大成对第三方的流量。某 resolver 带回之前选定的 Client Cookie,以及服务返回的 Server Cookie。验证成功,系统允许更完整的回答。

监控面板很容易把它写成“known client”。几分钟后,同一个公网地址可能已经承载 CGNAT 后的另一位用户;也可能有 on-path 设备复制了 COOKIE;还可能是某个 anycast 节点仍接受其他节点已经退休的旧 secret。字节在某处仍能通过,背后的操作者却未必相同。

这不是协议失效,而是 “weak authentication” 的准确含义。它回答的是数据包问题:在允许的时间窗和密钥 epoch 内,能够从这个源地址收包的一方,是否拿到过绑定于这个 Client Cookie 的服务器值?它不回答对方是谁、是否善意、请求是否应被授权,也不说明可以关闭所有其他保护。

真正的权力落在消费这个结果的 policy。validator 只提供一个事实;rate limiter、response-size control 和 abuse system 决定这个事实能换来多少资源。

两个 Cookie,职责并不对称

IANA 把 EDNS option code 10 分配给 COOKIE。客户端不知道服务器值时,RFC 7873 的首个请求只携带 8 字节 Client Cookie。服务器回应时附上 Server Cookie;后续请求带回两者。服务器据此验证,却不必维护庞大的逐客户端表。

Client Cookie 不是证书。RFC 9018 要求它对不同 server IP 使用不同值,建议有 64 bit entropy,在 client IP 变化时更新,也不应跨程序重启长期存在。它主要由客户端自己识别,服务器不能从中读出姓名、账号或组织。

Version 1 Server Cookie 固定 16 字节,完整 COOKIE option 因此正好 24 字节。SipHash-2-4 的输入包括 Client Cookie、版本、reserved、timestamp 和 client IP,密钥是服务端 secret。时间戳限制重放窗口;MAC 让 off-path 攻击者难以凭空造出新值。

stateless 降低攻击时的内存成本,却把风险集中到 secret、时钟和精确编码。非法长度不能被“尽量兼容”地解析;节点时钟偏差会改变接受范围;secret 扩散得越广,能制造有效 Cookie 的机器越多。一句 “cookies enabled” 证明不了这些控制是否一致。

有效 Cookie 只能购买有限特权

源地址伪造者收不到最初响应,通常也猜不中 Server Cookie。因此有效值可以成为“此前能够接收”的轻量证据,服务器可以据此放宽某些专为 anti-amplification 设置的限制,例如允许更大的 UDP 回答或更高的短时额度。

但 on-path 观察者能看到并复用它。Cookie 不加密查询,不签署 RRset,也不证明 resolver 没有被攻陷。DNSSEC 处理数据来源与否定证明;transaction ID、source port 等仍参与响应匹配;DoT、DoH、DoQ 提供另外的传输属性。这些控制回答不同问题,不能合并成一个 “secure DNS” 绿灯。

合理边界是:Cookie 只能影响其 threat model 直接覆盖的防御。它不应自动打开 recursion、绕过 access policy、跳过 DNSSEC、取消所有 rate limit 或覆盖 incident block。一个恶意或失陷 resolver 完全可能持续携带有效值。

源 IP 也不是稳定身份。NAT 聚合很多人,地址租约会变化,移动网络会切换出口。地址绑定对 off-path 威胁仍有价值,但网络位置的精确性不能被包装成社会身份的确定性。

Anycast 把 secret 变成共同责任

同一个 anycast 地址的连续请求可能落到不同城市、设备或软件实现。第二个节点必须能验证第一个节点生成的值,否则客户端会因路由变化反复变成“陌生人”。RFC 9018 因此统一 version 1 算法,并要求 Server Secret 可配置。

轮换有严格三阶段。第一阶段,所有节点先学会新 secret,仍用旧 secret 生成,并同时验证新旧。第二阶段,改用新 secret 生成,但继续验证旧值。第三阶段,等客户端刷新窗口过去后再彻底退休旧 secret。顺序错误会把局部配置差异放大成区域性 BADCOOKIE 风暴。

配置已下发不等于运行状态已一致。每个节点应暴露不含秘密的 epoch 标识,以及 learned、generating、accepting 状态和时钟健康。secret 应限制在真正需要互操作的最小 anycast 集合,不能因为方便而跨环境、跨客户、跨无关地址复用。

BADCOOKIE 是恢复信号,不是故障归因

Server Cookie 无效,可能因为过期、地址变化、Client Cookie 变化、节点 epoch 不一致、格式错误或伪造。BADCOOKIE 可以带回新值,让 Client Cookie 匹配的客户端重试;但重试必须有上限,不能形成无限循环。

同一个错误码背后有不同处置。只有一个 site 的 BADCOOKIE 偏高,优先调查 secret 分发。某移动网络突然升高,可能是 NAT 或出口变化。所有 site 同时收到异常长度,才更像 parser 探测或攻击。组织必须保留验证分类,再决定是否把流量定性为恶意。

只统计 valid ratio 会隐藏真实可靠性。还要看首次请求、expired、malformed、unknown epoch、BADCOOKIE、成功重试、放弃率和 TCP fallback。安全机制若让大量合法客户端无法完成解析,也不能算成功部署。

标准提供共同语言,运行数据决定现实

Heng Lu 的 Minimum Initial Specification 在这里非常具体:共同层只需要 option code、wire length、算法、时间语义、BADCOOKIE 与验证规则。全球不需要统一 response budget、DDoS policy、商业等级或 secret 托管机构。

Localized Future Decision 让服务器在容量不足时即使看到有效 Cookie 也能拒绝额外特权,让客户端遇到不支持 Cookie 的服务器时仍可继续解析。Voluntary Adoption 意味着 RFC 发布并不会让一个数据包自动受保护;只有实现、测试、部署和依赖它的运行事实才构成采用。

IANA codepoint 是符号协调。24 字节 option 是协议状态。放大响应的 policy branch 是可执行权力。实际发出的字节与影响是后果。running-code primacy 要求管理者用这些后果检验主张,而不是因为代码执行了就宣称行为必然正确。

来源