摘要

  • RFC 5393 记录了一种由不到十条合法 SIP 消息搭建、可能刺激出 2^71 条消息的分叉树;改成多个 AOR 后,即使所有代理都检测循环,路径在首次重复前仍可产生超过 N! 的流量。
  • Max-Breadth 约束活跃分支,并在分支收到最终响应后归还额度。它能压低瞬时状态与带宽峰值,但标准明确说明它不会减少攻击的累计流量。
  • 安全运营必须分别保存注册图、Via 历史、循环与螺旋判断、当前并发、累计分支,以及跨网关或 B2BUA 后是否仍保留同一段历史。

四个槽位可以循环使用

RFC 5393 为每个响应上下文定义 Incoming Max-Breadth 和 Outgoing Max-Breadth。前者是收到的并发额度;后者是已经分给下游、但尚未收到最终响应的额度总和。出站总和不得超过入站额度。

假设代理有八个目标,却只收到四个额度。它先并行打开四条分支。任何一条以失败响应结束后,该分支不再计入出站总和,释放出来的一个额度便可用于第五个目标。重复这一过程,八个目标都能被尝试,而活跃分支从未超过四。

这不是实现钻了标准漏洞,而是标准选择的折衷。工作组讨论过“额度一旦用过就永不归还”的方案。那会把一次请求的总事务数限制为初始 Max-Breadth 的常数倍,却也会大幅削弱合法请求的可达范围,被认为可能破坏既有部署。

因此,“分叉上限是四”必须补上单位。是同时四条,整个生命周期四条,最多四跳,还是每个 AOR 四条?RFC 5393 只承诺第一项。把并发图当作总成本图,会让一个完全合规的控制制造错误安全感。

放大器藏在合法注册关系里

最简单的场景使用两个代理/注册服务和四个 AOR。P1 上的两个地址都把 P2 上的两个地址注册为 Contact;P2 反向做同样的事。一个 INVITE 进入后先分成两条,再分成四条、八条。

每条消息都可以语法正确,账户也可以真实存在。倍增来自这些合法关系组合成的执行图。请求一直传播到 Max-Forwards 归零;按 RFC 3261 建议的初始值 70,二叉树含有 2^71 - 1 条请求。若处理时间超过 Timer C,还会叠加 408 与 CANCEL 风暴。

RFC 5393 还记录了 SIPit 互操作测试中的实际演示。参与代理超过两台,Max-Forwards 被限制为 20,系统仍相互轰击数小时。文档据此外推,最初那条 INVITE 需要接近十天才能处理完。一些代理重启后,只要注册状态仍在,就重新加入放大过程。

这不是对今天某个运营商的判断。它证明进程身份与因果状态不是同一层。重启可以得到一个新进程,却不会自动撤销持久注册图授予的路径权力。

循环检测只消灭已经重复的历史

在简单二叉场景中,循环检测非常有效。RFC 5393 说,只要任何参与代理检测,攻击就会立即停止;若所有代理都执行,第一种场景只产生 14 条受刺激消息,单服务器变体为 10 条。

因此,凡是把请求分叉到多个位置的代理,都必须确认自己没有参与循环。改进后的 Via branch 值包含第二部分,它依赖 Request-URI、实际参与转发判断的 Route 字段,以及位置服务使用的其他输入。代理再次看到自己的标记时重新计算:相同表示处理输入未变,应返回 482;不同表示请求以新的路由上下文形成螺旋,可以继续。

“循环”和“螺旋”是一项身份判断。取值过少,会让同一循环每次看起来都不同;取值过多,则可能把合法螺旋误杀。判断还依赖历史没有被下游改写。删除、混淆或更换 Via 分支参数,会让原节点失去识别自身路径的能力。

十个 AOR 在重复前已经走出近千万请求

更强的构造使用 N 个 AOR,每一个都分叉到完整集合。从 AOR 1 出发,在任何地址重复前,其余 N-1 个地址的所有排列都可以成为不同路径。每条路径末端再分叉 N 次,光最后一层就有 N! 条请求。

RFC 5393 的表格给出明确数值:四个 AOR 为 64,六个为 1,956,八个为 109,600,十个为 9,864,100。只要 N 不大于 Max-Forwards,即使所有代理都检测循环,总流量仍超过 N!。

这些数字不是普通 SIP 网络的预测。它们揭示了“去重”和“总量控制”之间的边界。循环检测可以阻止相同历史再次出现,却不能阻止首次出现的不同排列数量爆炸。每条路径都新,不代表所有新路径加起来仍然可接受。

深度、并发与累计工作是三个维度

Max-Forwards 管路径深度。Max-Breadth 管同时活跃的宽度。RFC 5393 明确禁止代理逐跳递减 Max-Breadth,把它偷偷当成另一个距离计数器。一次请求生命周期内累计打开多少分支,则是第三本账。

440 Max-Breadth Exceeded 也不是“工作结束”的凭据。它只说明当前代理无法在额度内执行想要的并行分叉,又不愿改为串行或重定向。Max-Breadth 为 1 时,串行分叉仍然允许。

标准在安全章节直说:Max-Breadth 不减少分叉循环攻击造成的累计流量,只是通过限制并发,把流量摊到更长时间。攻击者还能投入多条根请求,逐渐堆出不合理负载。

这项控制真正买到的是干预时间。较低峰值可以让系统活得足够久,等运营者发现某个资源的未完成事务缓慢上升,或发现全网同时上升,再临时停用相关资源。但若没有累计监控,慢速攻击只是更不显眼,不是更便宜。

B2BUA 可以让历史断裂,而工作继续

B2BUA 在一侧结束 SIP,会在另一侧产生新的请求。拓扑隐藏可能有合理目的,但也可能删掉 Via、Max-Forwards 或 Max-Breadth 所依赖的连续历史。RFC 5393 警告:若两个这类边界都以为自己能单独处理循环,最终可能谁也看不到完整回路。

RFC 7332 后来要求 B2BUA 复制并递减 Max-Forwards,把 Max-Breadth 从 UAS 一侧带到 UAC 一侧并按代理规则执行,同时建议实施 RFC 5393 的循环检测。它也承认一种真实冲突:历史可见性支持安全,拓扑混淆支持另一类隐私或商业目标。

字段存在仍不等于控制在运行。运行代码优先要求用真实路径做探针:比较边界两侧的值,验证并行请求共享同一入站额度,确认 482 能穿过或在正确位置发生。产品说明书不是执行回执。

证据边界

被冻结的来源证明 RFC 的文本、状态、所记录的 SIPit 情况与规范要求。它们不证明当前厂商采用率、现实攻击频率、近期事故原因或某个网络的配置。2^71、N! 与 9,864,100 都必须绑定各自构造。

最稳固的结论并不夸张:并发上限是一张瞬时照片,安全还需要生命周期账簿。账簿要回答谁创建了分支、依据什么历史、额度归还了几次、路径走了多远,以及这些工作最终是否换来真实用户结果。