摘要

  • RFC 862 的 UDP Echo 把收到的数据原样送回;RFC 864 的 UDP Character Generator 不理会请求内容,只生成一份长度为零至 512 字符的回答。
  • 攻击者只要把首个请求的来源伪造成 Echo 服务,就能让 Chargen 回答 Echo、Echo 再回答 Chargen,此后的往返不再需要发起者参与。
  • BCP 38 直接记录了这条回路,并把控制移到服务暴露与源前缀校验边界;后续规范又补上适应多宿主路由的过滤、对端验证、限速与熔断。

回来的包没有真正的提问者

观察这条回路时,最容易误读的是每一份单机日志。Chargen 记录一次入站请求和一次出站回答;Echo 也记录一次入站请求和一次出站回答。两边都没有“多发”第二个包,也没有越过各自协议规定的次数。

把两份时间线接起来,因果关系才显露:Chargen 的出站包就是 Echo 的入站包,Echo 的出站包又是 Chargen 的下一份入站包。数据包并非由一个持续发言的人推动,而是由上一轮回答推动。发起者只负责把首个包的源地址写成另一个服务,让错误身份把两套正确动作闭合起来。

这不是定向广播故事。网络不必把一个包复制给整段子网,也不必出现许多接收者。两台单播主机、两个 UDP 应用就足以形成反馈。它也不依赖某个固定放大倍数;核心风险是工作能够自我续接。

两件为诊断而造的简单工具

RFC 862 在 1983 年把 Echo 描述为调试和测量工具。TCP 版本在连接关闭前不断送回收到的数据;UDP 版本使用端口 7,每收到一只数据报,就把其中的数据装进回答数据报送回。

RFC 864 定义的 Character Generator 也服务于测试。TCP 版本连续输出字符,并依靠 TCP 流量控制约束速度。UDP 版本位于端口 19:收到任何数据报后,不解析内容,随机选择零到 512 个字符,发送一只回答数据报,而且不保存跨请求历史。

这种简洁曾是优点。测试者不需要账号、命令语言或会话协商,就能检查双向连通、字符传输与吞吐。但两项服务也因此不掌握一条关键事实:眼前这只“请求”是否其实是自己上一轮回答经过另一项服务反弹后的结果。

RFC 768 提供了最小运输机制。UDP 数据报带有源端口、目的端口、长度和校验和;请求中的源端口可以告诉接收应用把回答送往哪里。这里没有建立连接的握手,也没有由传输层创建的、经过认证的对端关系。

“每次只答一个”只约束了局部

RFC 864 曾用一问一答解释 UDP Chargen 不会比请求到达得更快。若只把服务看成一个函数,这句话没有错:一次调用只产生一份回答,服务自己不会无缘无故再调用一次自己。

但系统由函数的连接方式组成。一个组件的输出若能成为另一个组件的输入,“回答一次”只是环路的一条边,而不是交易的终点。安全审查若只数单次调用的输出数量,就会漏掉输出重新进入输入通道的路径。

这也是为什么合规日志可能与事故同时成立。每端都能证明自己按文档执行,整套系统却没有终止条件。判断系统是否有界,需要追踪因果链,而不仅是检查单个处理器的响应上限。

BCP 38 把回路写进了规范

RFC 2827,也就是常说的 BCP 38,并非只泛泛讨论地址伪造。它明确举出一类攻击:伪造 UDP 包,把一个站点的 Character Generator 服务与另一个站点的 Echo 服务接在一起,随后两者持续向对方发包。

文档先给出最直接的暴露控制:这类诊断端口不应从管理域外部可达。只要外来包走不到服务,攻击者就无法借它闭合回路。这项决定不改变协议,却改变谁有权触发它。

另一项控制位于客户网络进入服务商的边界。服务商应检查出站包所声称的源地址是否属于该客户合法发布的前缀。若不是,就在它继续传播之前拒绝。这个动作限制下游网络可以向互联网输出哪些身份主张,也把调查范围收窄到允许该前缀的入口。

“入口过滤”容易让人误以为它发生在受害者门口。BCP 38 的责任更接近源头:流量从客户进入上游时,上游不应替明显不属于客户的源地址背书。

前缀可信不等于主机可信

RFC 2827 同时写明边界。若受控主机伪造同一合法前缀内另一台主机的地址,普通前缀检查仍会放行。攻击者也可以使用自己的真实地址制造洪泛。因此,BCP 38 削减一类谎言,却没有把 IP 源字段变成身份证明。

多宿主与非对称路由又增加了执行难度。RFC 3704 讨论严格、可行路径、宽松反向路径检查以及访问列表。严格模式要求最佳回程路径与入站接口一致;正常流量若去程和回程不同,也可能被误判。

所以,运营者面对的是多种证据强度。宽松检查能排除路由表中根本不存在的来源,却允许更多伪造;可行路径能容纳更多合法入口,却依赖充分路由信息;明确 ACL 较精确,但必须跟随客户前缀更新。过滤政策只有与真实拓扑一起验证,才是可运行的控制。

新一代 UDP 指南补上对端与熔断

RFC 8085 把教训扩展到一般 UDP 应用。所谓“连接”本地 UDP socket 可以让操作系统只交付特定来源的数据报,却不会通知远端,更不会凭空建立认证关系。应用若要求消息确实来自某个对端,就必须自行验证,或明确委托系统过滤。

UDP 也没有内建流量控制。规范要求应用避免用很短请求触发很大回答,不应把可伪造的源 IP 当成认证,并应对高成本响应增加授权、限速或其他约束。熔断机制则为无状态交互补充最小历史:即便这一包语法正常,连续发送是否仍有根据?

这些措施不能互相冒充。关闭公网暴露不能证明内网主机诚实;源前缀校验不能识别同一前缀内的主机;限速能减小代价,却不修复身份;应用认证很强,但对一项无需公开的古老诊断服务而言,更合理的选择可能是根本不开放。

端口号只回答“在哪里约定”

今天的 IANA 服务名与传输端口号登记表 仍列出 TCP/UDP 端口 7 的 echo 与端口 19 的 chargen。稳定编号让不同实现知道到哪里寻找共同功能。

登记并不证明某台主机正在运行服务,也不证明它对公网开放、符合旧 RFC 或得到运营者授权。安全分析不能只凭目的端口下判决。它还需要方向、载荷、时序、端点归属,以及“这一回答是否紧接着触发对端下一请求”的因果证据。

回路把权力边界照得更清楚

Echo 与 Chargen 本身不是隐蔽恶意程序。它们把两项诊断动作写得极其透明。危险产生于组合:伪造身份把两个回答权连接起来,而任何一端都看不见完整路径,因此都不知道何时该撤回权力。

持久的设计原则不是“无状态一定危险”,也不是“UDP 一律不该回答”。真正的问题是:输出能否重新成为输入,源字段是否足以支配回答方向,谁能在回路出现时中断权限,以及监控系统能否把分散事件还原成同一条因果链。

互联网对它的治理仍然是分布式的。运营者控制可达性,接入网络限制源声明,应用核验对端与响应成本,监控连接请求和回答。没有中央设备替所有层作决定;安全来自各层只对自己能验证的证据负责。

来源与证据边界

这些来源能够证明协议行为、BCP 38 记录的回路、过滤方法与后续 UDP 指南。它们不能给出当今服务暴露数量、攻击频率、平均响应比或全球 BCP 38 部署率。本文因此只论证机制与控制边界,不把历史示例写成当前规模统计。