跳至正文
网络安全

如何按 /64 前缀对 IPv6 滥用进行限流和封禁

IPv6 限流要按前缀而不是按地址:一个用户拥有一整个 /64。以 /64 作为限流和封禁的键,逐步升级到 /56 和 /48,并让信誉随时间衰减。

作者GeoIPHub 团队发布于更新于阅读时长阅读约 23 分钟
由无数小格组成的区域,一块半透明的板覆盖了其中一大块,代表一个 IPv6 /64 前缀

生产环境中几乎所有的限流器、登录节流和 IP 封禁列表都是针对 IPv4 设计的,那里的思维模型很简单:一个地址,大致对应一个用户。按地址统计请求,封禁地址,然后继续。这个模型已经悄然失效。一旦您的流量中包含 IPv6(而且这部分占比很大并且还在增长),您所计数的单位就不再对应一个人,所有建立在“一个地址”之上的防御都会出现漏洞。

这不是一个微妙的边缘情况。它决定了限流器是真正有效,还是让攻击者长驱直入,而您的仪表盘上只显示一排整整齐齐、每个只有一次请求的地址。解决办法不是增加更多规则,而是统计正确的对象,这与按 IP 地址段验证 AI 爬虫和 bot 背后的习惯相同:公布的 CIDR 地址块比任何单个地址都更重要。前缀计数是通过 IP 地址检测 bot 的一层,其他几层则告诉您该前缀属于哪类网络。

地址区域上方三块逐级增大的嵌套板,分别代表 /64、/56 和 /48 前缀
在 IPv6 中,前缀才是用户;限流要针对 /64,而不是单个地址。

在 IPv6 上失效的 IPv4 习惯

在 IPv4 上,地址稀缺反而帮了您的忙。总共只有约 43 亿个地址,价格昂贵,而绝大多数情况下,一个用户同一时间只拥有一个公网地址。所以“来自这个 /32 的请求”和“来自这个用户的请求”足够接近,可以视为同一回事。封禁一个 /32,最多影响到这个家庭或它背后的 NAT。

IPv6 消除了稀缺,随之消除了这个假设。地址长度从 32 位变为 128 位(八组、每组四位十六进制数字),设计理念与节约正好相反。IPv6 不是按单个地址配给,而是给每个客户分配一整个地址块。任何人能分到的最小地址块都非常庞大,而真正代表用户身份的是这个地址块,而不是单个地址。

如果您的限流器在 IPv6 上仍然按完整地址计数,滥用者既不需要僵尸网络,也不需要代理池。他们只需要一个普通的 IPv6 地址分配和一个 for 循环。

一个用户,1800 亿亿个地址

这个数字会彻底改变您看待问题的方式。IPv6 终端用户通常分到的最小可路由地址块是 /64:前 64 位是网络部分,后 64 位由用户随意填写。这意味着单个用户的子网内有 2^64 个可用地址:

2^64 = 18,446,744,073,709,551,616 个地址:约 1844 亿亿个,全部属于一个用户,全部同样可路由。

有两个事实决定了这是必然结果而不是偶然现象。第一,无状态地址自动配置(SLAAC)是 IPv6 主机自行分配地址的标准方式,它要求每个子网使用完整的 /64;对于普通局域网,无法分配更小的地址块。第二,各 RIR 遵循的地址规划指南(RFC 6177 / BCP 157)要求 ISP 给每个终端站点慷慨地分配地址,通常是 /56 或 /48,并且绝不少于 /64。地址充裕正是这个协议的核心。

再看攻击者这一边。在这些地址之间轮换既不昂贵也不需要技巧,它只是一个内置的 socket 选项。Linux 的 IP_FREEBIND 标志允许进程绑定到本地路由前缀内的任意地址并从中发送数据,而无需事先在网卡上逐一配置这些地址;公开工具,例如被广泛引用的 freebind 项目,正是把这一点封装成了“每个连接使用一个全新的源地址”。给它一个已路由的 /64,它就能以零成本从 1800 亿亿个不同来源发出流量。

所以按 /128 限流对这种攻击毫无减速作用。每个请求看起来都是一个只出现过一次的全新地址。限流器的计数器永远不会超过一,封禁列表里塞满了数百万条只命中一次、什么也匹配不到的记录,而攻击则全速进行,在纸面上看起来分布得完美均匀。

IPv6 分配层级及各层的含义

要对正确的单位限流,您必须知道每个前缀长度实际代表什么。IPv6 前缀就是 CIDR 地址块(与 IPv4 使用相同的 /n 表示法,数字越小覆盖的地址越多),但约定俗成的边界能够说明另一端是谁。

前缀包含代表谁 / 什么可以按此聚合吗?
/1281 个地址单个接口,是一个用户的千万亿亿个地址之一。可免费轮换。不能。这正是常见错误。绝不能作为计数单位。
/64一个子网(2^64 个地址)单个用户的局域网。能够保证对应一个用户的最小地址块。可以。这是默认的限流和封禁键。
/56256 × /64ISP 给家庭或小型企业的典型分配。可以,在滥用持续时:一个客户的全部分配。
/4865,536 × /64较大站点或企业的分配。可以,在滥用持续时;通常仍是同一个实体。
/3243 亿 × /64整个 ISP 或托管服务商的分配。很少。这是整个网络,有成千上万的用户。

决策的形态从表中自然得出。/128 永远不是计数单位。/64 是下限:仍然对应一个行为者的最窄范围,因此也是默认值。任何更宽的范围都是一种升级,只有当您有证据表明更大的分配整体上存在问题时才使用。

规则一:按前缀对 IPv6 限流,从 /64 开始

解决大部分问题的唯一改动,就是不再按地址计数,而是按 /64 计数。具体来说,对每个传入的 IPv6 请求,保留前四组十六进制段(64 位)得出 /64,并把它作为限流计数器、登录尝试计数和封禁列表查询的键。

GeoIPHub API
// Normalize any IPv6 address to its /64 aggregation key. // The first 64 bits (4 hextets) identify the subscriber's subnet; // the last 64 bits are theirs to rotate through, so we discard them. function ipv6Key(addr) { // Expand "2001:db8::1" to full form, take the first four groups. const full = expandIPv6(addr); // 8 groups of 4 hex digits return full.split(":").slice(0, 4).join(":") + "::/64"; } // "2001:0db8:85a3:0000:0000:8a2e:0370:7334" -> "2001:0db8:85a3:0000::/64"

所有主流边缘工具都已经支持这一点,所以您很少需要自己实现:

  • nginx: 用一个把 IPv6 掩码到 /64 的 map/geo 块构造限流键,然后把它传给 limit_req_zone / limit_conn_zone,而不是使用 $binary_remote_addr。
  • HAProxy: 构造 stick-table 键时对源地址设置 64 位掩码,使 src 按 /64 聚合,而不是按完整地址。
  • Cloudflare 及大多数 CDN / WAF: 在自身的限流和质询逻辑中已经按 /64 地址块处理 IPv6;在源站规则中采用同样的粒度,让两层保持一致。
  • 您自己的应用限流器: 在原始 remote_addr 进入 Redis、令牌桶或计数器之前,就把它替换为上面的 /64 键。

只要做到这一点,免费轮换攻击就会回归它应有的样子:1800 亿亿个地址变成一个计数器,滥用者受到的节流与单个 IPv4 地址完全相同。这是整个话题中价值最高的一行代码。

规则二:在滥用持续时升级到 /56 和 /48

以 /64 为键可以应对在一个子网内部轮换地址的攻击者。阶梯上的下一步是轮换子网的攻击者,因为一个用户往往持有的不是一个 /64,而是装满 /64 的一整个 /56 或 /48,而 freebind 一类的工具同样可以在它们之间游走。

扩大范围的信号是持续性:共享同一个父前缀的新 /64 不断出现不良行为。看到这种情况时,整个分配就是同一个实体,应当作为一个整体处理。

您观察到的情况含义处理
来自一个 /64 的滥用来源是单个子网。对该 /64 限流 / 封禁。
同一个 /56 内反复出现新的 /64一个家庭/中小企业分配在轮换子网。把计数器和封禁升级到 /56。
滥用分布在整个 /48整个站点分配都有敌意。升级到 /48;通常仍是同一个客户。
一个 /32 内的许多 /48来自整个 ISP 地址空间的噪声。不要封禁 /32;改为对各个前缀分别评分。

可以把它想象成一个逐级汇总的计数器。以 /64 计数作为基本单位,同时跟踪汇总到每个 /56 和 /48 的滥用情况。当某个父前缀越过任何单个合法客户都不会达到的阈值(短时间内有许多不同的子 /64 都在违规)时,就在父级应用限制,让它一次覆盖所有子前缀。这样您就能领先于拥有大块分配的攻击者,同时不会惩罚那些拥有小块分配且行为良好的用户。

规则三:根据网络类型扩大范围,而不是凭直觉

升级有一种失败模式,而且代价高昂:范围扩得太宽,一次封禁就会抹掉成千上万的无辜用户。一个 /48 可能是一家企业,也可能是移动运营商的一部分。一个 /32 几乎从来不是单一行为者,它通常是整个 ISP 或托管服务商。持续性信号告诉您父前缀参与了滥用,但没有告诉您它背后有多少真实用户。要知道这一点,您需要了解该前缀属于哪类网络。

这正是 IP 查询在处理流程中发挥作用的地方。对违规前缀中的一个代表性地址调用一次 IP 查询 API,就能知道您面对的是可以激进聚合的租用基础设施,还是必须温和对待的消费者接入网络。

GeoIPHub API
curl -H "x-api-key: YOUR_API_KEY" \ https://api.geoiphub.com/v1/lookup/2001:4860:4860::8888

决定您可以安全扩大到多宽的字段:

GeoIPHub API
const res = await fetch(`https://api.geoiphub.com/v1/lookup/${addr}`, { headers: { "x-api-key": process.env.GEOIPHUB_API_KEY }, }); const ip = await res.json(); ip.asn.asn_type; // "hosting" | "isp" | "mobile" | "cdn" ... ip.asn.connection_type; // "datacenter" | "residential" | "mobile" ip.asn.carrier; // set for cellular networks: a leniency signal ip.detection.is_hosting; // true: infrastructure, aggregate up freely ip.threat.is_cgnat; // shared address space; do not widen a hard ban ip.scoring.fraud_score; // 0-100 composite, when you must decide per-address ip.scoring.recommended_action; // "allow" | "review" | "step_up" | "block" ip.scoring.detection_methods; // exactly which signals fired: your audit trail

以下是对一个真实 IPv6 地址的查询结果,即 Google Public DNS 的 2001:4860:4860::8888,查询时间为 2026-10-05(已精简;结果会随地址段变动而变化):

GeoIPHub API
{ "ip": "2001:4860:4860::8888", "asn": { "asn": 15169, "org": "GOOGLE - Google LLC", "asn_type": "hosting", "connection_type": "datacenter", "carrier": "none" }, "detection": { "is_proxy": false, "is_vpn": false, "is_tor": false, "is_hosting": true, "is_mobile": false }, "threat": { "is_cgnat": false }, "scoring": { "fraud_score": 15, "recommended_action": "allow", "detection_methods": ["datacenter_ip", "no_ptr_datacenter"] } }

响应的两部分回答了两个不同的问题。asn_type: "hosting"、connection_type: "datacenter" 和 is_hosting: true 表明该前缀是基础设施,所以把封禁扩大到 /64 以外不会波及家庭用户。但 scoring.fraud_score 是 15,recommended_action 是 allow:这个地址本身没有 VPN、Tor 或滥用信号,detection_methods 只列出了 datacenter_ip 和 no_ptr_datacenter。网络类型告诉您可以扩大到多宽;而是否需要扩大,理由必须来自您自己的持续性计数器。一个从未出现不良行为的托管前缀应当保持开放。

这种解读是有方向性的,与会加分也会减分的风险评分原因背后的原则相同:有些字段让您可以更强硬地处理,另一些则提醒您收手。

网络类型宽前缀内包含什么升级到多宽
托管 / 数据中心租用的服务器。真实的购物者不在这里。激进。一个有敌意的托管 /48 可以整体封禁。
住宅 ISP家庭用户,在更宽的前缀下每户一个 /64。谨慎。封禁保持在 /64 到 /56;/48 可能包含许多家庭。
移动 / 蜂窝网络运营商用户,经常共享更宽的地址空间。窄范围。一个运营商 /32 覆盖一个国家的手机;绝不硬性封禁。
CGNAT / 共享许多用户位于共享地址空间之后。评分,不封禁。像对待共享 IPv4 地址一样处理。

Google Ads 也是这样计数的:它的 API 把 2001:db8::/48 视为一个 IP 排除条目,所以一个 /48 会占用您 500 个 Google Ads 排除名额中的一个。

这条原则我们在检测匿名流量而不误伤真实客户中做了完整论证:在 hosting 或 datacenter 前缀上,您可以放心扩大封禁范围,因为结账或注册没有任何正当理由来自一排服务器机架。这与我们在什么是数据中心 IP 地址中剖析的特征相同。在 mobile 或 residential 前缀上,要保持窄范围,让风险评分而不是宽泛的 CIDR 封禁来承担主要工作。凭直觉扩大范围,正是限流器悄然变成真实用户故障的原因。

规则四:让前缀信誉随时间衰减

最后一条规则关于时间。IPv4 封禁列表本来就会因为地址被重新分配而过时;IPv6 让情况更糟,因为整个前缀会被委派、归还、再委派,上个月猛攻您登录页的 /64,今天可能属于一个普通家庭。在轮换的地址空间上维护永久封禁列表,最终会变成一份您再也无法安全访问的地址清单。

所以不要为每个前缀存储永久结论,而是存储一个会变动的信誉:

  • 滥用时提高。 每个违规请求都会提高该 /64 的评分,并以较小的增量向其父级 /56 和 /48 汇总。
  • 随时间衰减。 如果一个前缀保持安静,它的评分会按计划下降(软节流按小时计,硬封禁按天计),直到回落到阈值以下,封禁自动解除。
  • 依据当前评分而不是历史采取行动。 根据信誉当前所处的位置决定限流、质询还是封禁,这样改过自新或被重新分配的前缀会自动恢复,而不是一直留在一份无人清理的列表上。
  • 保留证据。 记录每次评分变化的驱动信号(查询返回的 detection_methods、持续性模式),让一次宽范围封禁成为您能够解释的决定,而不是一条神秘的记录。

衰减让整个系统保持公正。它意味着攻击期间的激进升级不会成为永久的伤疤,也意味着您的封禁列表反映的是现在谁有敌意,而不是谁曾经有过敌意。

本周就开始

  • 把限流键切换为 /64。 在当前按地址计数或封禁的所有地方,先把 IPv6 掩码到前 64 位。这一项改动就能堵住免费轮换的漏洞,在 nginx、HAProxy 或您的应用中通常只需几行代码。
  • 为 /56 和 /48 添加汇总计数器。 跟踪汇总到父前缀的滥用情况,使轮换子网的攻击者触发更宽的限制,而无需您默认扩大范围。
  • 扩大范围前先查询网络。 每次升级超过 /64 时,检查 asn_type / connection_type:对托管网络放开聚合,对移动和住宅网络保持窄范围,绝不硬性封禁运营商或 CGNAT 地址段。
  • 对模糊情况进行评分。 当前缀是共享的或属于消费者网络时,按地址使用综合 fraud_score 和 recommended_action,而不是简单粗暴的 CIDR 封禁。
  • 为每次封禁设置衰减。 用半衰期存储前缀信誉,依据当前评分采取行动,让被重新分配的地址空间自动解封。

与其说 IPv6 让滥用防护变得更难,不如说它改变了计数单位。地址不再是用户,/64 才是。统计它,凭证据升级,按网络类型加权,让时间来完成宽恕。这样,您在 IPv4 上信赖的每一种防御都会重新生效。

常见问题

为什么不能像对 IPv4 地址那样对 IPv6 地址限流?

因为两种协议分配给每个用户的地址空间相差极大。在 IPv4 上,一个用户通常只有一个地址,所以按 /32(单个地址)限流就等于按用户限流。在 IPv6 上,一个用户通常会分到一整个 /64。那是 2^64 个地址,约 1844 亿亿个,而 IP_FREEBIND 之类的工具可以让一个进程免费从该地址块中的任意地址发出流量。因此,对单个 /128(单个 IPv6 地址)进行限流或封禁毫无作用:滥用者只需换用 1800 亿亿个地址中的下一个。IPv6 上正确的计数单位是 /64,而不是 /128。

IPv6 应该按多长的前缀限流?

从 /64 开始。/64 是能够保证属于单个终端用户的最小地址块,因为 SLAAC 要求每个子网使用完整的 /64,而 ISP 至少会给每个客户分配一个 /64。把计数器和封禁列表的键设为地址的前 64 位,并把整个 /64 视为同一个行为者。当同一客户的滥用行为跨越多个 /64 持续出现时,把范围升级到 /56(256 个 /64),再到 /48(65,536 个 /64),这两者是整个家庭或企业分配的典型大小。

封禁整个 IPv6 /64 安全吗?

几乎总是安全的,而且比封禁单个 IPv4 地址更安全。/64 在设计上就是一个用户的子网,所以封禁它很少会像共享的 IPv4 CGNAT 地址那样误伤无关的人。真正的风险在更宽的前缀上:一个 /48 或 /32 可能是整个 ISP、一家移动运营商,或覆盖数千个无关用户的共享主机地址段。只有在网络类型证明合理时才扩大范围:对托管/数据中心前缀可以激进,对移动和住宅前缀要谨慎。

如何判断封禁应该升级到多宽?

由两件事决定:持续性和网络类型。持续性:如果滥用不断从同一个 /56 或 /48 内的新 /64 中出现,那么整个分配就是同一个实体,应扩大到这一层。网络类型:如果查询返回托管或数据中心 ASN,说明该前缀是基础设施,可以快速向上聚合;如果是移动运营商或住宅 ISP,说明更宽的前缀背后可能有许多真实用户,应保持较窄的范围,依靠风险评分而不是硬性封禁。

CGNAT 和移动网络会改变 IPv6 的处理方式吗?

会,在宽前缀这一端。即使在移动网络上,一个 IPv6 /64 通常也只对应一个用户,所以按 /64 限流仍然正确。但移动运营商和 464XLAT/NAT64 部署可能把许多用户放在一个共享的更宽前缀下,因此对移动 ASN 进行 /48 或 /32 范围的封禁,可能会波及运营商的大量客户。规则与 IPv4 相同:绝不因为一个坏行为者就硬性封禁一个共享地址段。对它评分,把宽范围封禁留给基础设施前缀。

IPv6 前缀应该被封禁多久?

不应永久封禁。IPv6 前缀会被重新分配,上个月滥用过您服务的 /64,下个月可能就属于另一个客户了。为每个前缀附加一个会衰减的信誉,而不是一条永久记录:发生滥用时提高其评分,如果一段时间内没有不良行为就让评分下降,一旦衰减到阈值以下就自动解除封禁。在轮换的地址空间上维护永久封禁列表,最终会变成一份您再也无法安全访问的地址清单。

作者

GeoIPHub 团队

GeoIPHub API 背后的团队

由 GeoIPHub 团队撰写,即构建 GeoIPHub IP 情报 API 及其扫描器的团队。草稿在 AI 辅助下完成,并由团队编辑;除非标注为示例,API 示例均为针对线上 API 的真实查询。

分享本文
更多文章

相关 文章