摘要

  • DNS 对 ASCII 字母实行大小写不敏感比较,却常常原样抄回查询区。2008 年的 DNS-0x20 草案试图把这种“含义无关、表示仍在”的空间变成本次查询的临时挑战。
  • 每个可变换的 ASCII 字母最多贡献一位,但效果取决于名字里有多少字母、全路径是否保持原样,以及解析器能否妥善处理压缩、缓存与降级。它从来不是 DNSSEC,也没有成为正式 RFC。

同一串名字,在两个时刻接受两种审查

解析器发出查询时,可以把每个英文字母随机写成大写或小写。权威服务器查找记录时不应在意这种排列:从 DNS 的意义看,它仍是原来那个名字。回包抵达后,解析器却不再只问“这是不是同名”,还要问“问题区是否逐位带回了我刚才选择的排列”。

第一项判断解决名称指向什么,第二项判断这个应答是否像是针对眼前这笔未完成查询而来。两者的适用范围不同,所以并不矛盾。离路径攻击者可能知道查询的名字,也可能猜测事务标识符,却未必知道这一刻临时生成的大小写图案。

DNS-0x20 的巧思就在这里。它没有申请一个新字段,也没有把大写域名和小写域名拆成两个对象;它只是暂借协议已经宣布“不承载名称差异”的表示空间。

1987 年留下的不是安全位,而是一条接缝

RFC 1035 把 DNS 协议中的字符串比较规定为大小写不敏感。只在 ASCII 字母大小写上不同的两个名称必须被当作相同名称。但同一份文档又要求系统在可行时保留原始大小写,并尽量减少大小写信息的损失。

这是一项互操作折衷。大小写不能把命名空间劈成互不相认的两半,否则用户输入、数据库存储和跨系统解析都会变得脆弱;与此同时,运营者录入的写法与查询者发送的形式仍有展示价值。协议抹去了身份差别,却没有命令每一层都立即抹去外观。

RFC 4343 后来把边界说得更清楚。这里的折叠针对 ASCII 的 A-Z 与 a-z,不等于可以套用任意自然语言的大小写规则,更不能把 DNS 比较同 IDNA 转换混为一谈。它还提醒,输出端未必总能保留原样:只按一个节点存储数据时只能留下某一种写法,名称压缩也可能让应答中的标签借用消息其他位置的字节。

因此,0x20 不是从规范中发现了一组保证可用的安全位。它发现的是一条有条件存在的接缝:大小写不决定查到哪组记录,但在许多实现里仍能随问题区往返。

一次查询借走一次表示冗余

2008 年 3 月的 Internet-Draft《Use of Bit 0x20 in DNS Labels》提出,对问题名称中的每个 ASCII 字母随机翻转 0x20 位。这个位区分 ASCII 大小写。权威端照常进行不区分大小写的匹配;发问端则在本次查询尚未结束的时间里,把每种排列视为不同的挑战值。

草案依赖一个当时常见、但旧规范没有明文保证的习惯:服务器会把请求的问题区原样复制到应答。草案作者列出一批 2008 年测试过的权威实现,称它们逐位抄回问题名称;同时也承认少数实现会统一转成小写。解析器若保存了自己发送的排列,便可在事务 ID、端口、类型和类别都吻合之后,再拒绝一个大小写图案不符的回包。

RFC 5452 提供了理解这件事所需的背景。解析器不是只看 16 位事务 ID;问题名称、源与目的地址、端口、查询类别和类型共同组成匹配条件。充分随机的 16 位 ID 平均仍只需 32768 次猜测,随机源端口可以扩大搜索空间。0x20 方案想利用已经位于 QNAME 内部的字节,再增加一组攻击者必须同时猜中的状态。

它是加法,不是替代。大小写随机化不会补救可预测的随机数,不会证明应答来自区域授权者,也不会让一份未签名数据突然获得真实性。

强度随名字本身改变

只有可变换的 ASCII 字母能携带这种临时位。数字与连字符不贡献大小写选择;短而少字母的名字可提供的组合明显少于长而多字母的名字。草案甚至用不同名称说明,有的能增加十二位,有的只有六位。

于是,“已开启 0x20”不是一个完整的安全度量。同一个解析器面对不同名称时,新增猜测空间并不相等;同一个名称经过不同路径时,存活到应答端的位数也可能不同。真正需要计数的是本次问题包含多少合格字母、生成是否不可预测、回显是否逐位保留,而不是配置页上的一个开关。

非 ASCII 标签也不能被自然地算进来。RFC 4343 特意把 DNS 的 ASCII 折叠与国际化名称处理分开。把某种语言的大小写观念直接施加到线上标签,已不是扩展 0x20,而是在改变协议对象。

中间设备可以不改含义,却抹掉暗号

一个转发器、检查设备或权威实现可以把问题名称全部转成小写,同时仍然把查询送到正确区域、返回正确 RRset。站在基础 DNS 语义上,它没有把名字弄错;站在 0x20 校验上,它已经销毁了挑战。

这种冲突揭示了方案真正依赖谁。随机图案由解析器产生,但能否存活由沿途软件共同决定。草案中的测试只能说明作者在 2008 年观察过什么,不能把所有后来路径都变成承诺。

大小写不符也不是攻击证明。它可能来自伪造包,也可能来自正常化行为、路径差异或缺陷。较稳妥的处置是记录具体权威地址和路径,丢弃眼前回包,再尝试同一区域的其他服务器;不能把一位发生变化直接升级成“已遭投毒”的结论。

回包验证之后,必须把临时状态擦掉

DNS-0x20 最容易被忽略的设计,不是如何制造随机图案,而是何时恢复原样。

DNS 应答会用名称压缩指针。答案区、权威区或附加区中的名称可能不再重复标签,而是指回问题区。如果解析器在核对大小写后立即解压并缓存消息,随机图案就可能顺着指针进入持久缓存,再被后续应答带给别的查询者。

草案因此要求解析器记住原问题名称:先核验随机排列,成功后把问题区恢复,再解压其他部分。临时交易状态必须在跨入共享状态之前终止。否则,一次查询用来增加猜测成本的外观,会污染许多与它无关的后续表示。

这条清理顺序比“多几位熵”更具普遍意义。任何系统若把格式冗余借作 nonce,就必须同时规定归还时点。只有生成而没有擦除,防护链条并未闭合。

兼容回退本身就是控制面

严格拒绝大小写不符的应答,可以保住挑战,却可能把会统一小写的服务器判成不可用。第一次不符就关闭校验,可以维持可达性,却给攻击者留下诱导降级的空间:只要制造不符,便可能让解析器放弃额外检查。

过期草案给出的思路更昂贵。先轮询区域的其他权威地址;若全部不回显,再用新的事务 ID 和其他随机元素重做完整序列,最好还改变服务器次序。只有当其他随机字段多次被正确带回,而大小写持续遭到同一种改写时,解析器才较有理由把它识别为兼容性问题。

代价同样真实:查询量和延迟会上升,不保留大小写的权威端可能承受数倍请求,随机数生成器也会向外暴露更多连续输出。这里没有无需治理的免费安全位,只有伪造成本、可用性、负载与降级风险之间的选择。

DNSSEC 对同一批字母作出相反处理

RFC 4034 为 DNSSEC 签名与验证定义规范化 RR 形式:名称应展开,不使用压缩;相关位置的 ASCII 大写字母转成小写。所有验证者必须得到同一串规范字节,签名才有稳定对象。

于是,两种机制碰到同一个大小写差别,却向相反方向使用。0x20 希望一次往返中保留随机外观;DNSSEC 为认证数据而消除外观差异。前者提高盲猜一次交易状态的难度,后者验证签名 RRset 是否由相应信任链授权。精确回显不等于来源认证,更不能代替 DNSSEC。

一份过期草案留下的历史问题

DNS-0x20 文档在 2008 年 9 月过期。它不是正式 RFC,文中的实现清单也不是今天的部署普查。准确的历史表述应停在这里。

但它留下了一个耐用的工程问题:协议为了互操作而放弃的差别,是否还能被一方短暂利用?答案并非简单的“可以”。只有当系统能计算实际位数、核对路径依赖、解释不符、抵抗回退降级,并在缓存之前清除状态,那份冗余才真正成为防护资源。

大写字母没有获得命名权。它们只在一笔未完成查询里,成了回包必须原样带回的暗号。

来源与限度

本文依据 RFC 1035、RFC 4343、RFC 5452、RFC 4034 以及 2008 年 3 月的 DNS-0x20 Internet-Draft。这些材料没有证明当代产品默认值、全球启用比例或所有路径的兼容率;草案中的实现结论仅代表作者当时的测试。