如何阻止虚假注册:按 IP 类型检测虚假账户
按 IP 类型阻止虚假注册:2026 年 11 月 2 日的七次实时查询、每种地址应得的注册处理,以及可用于您自己代码的 /24 与 /64 频次限制。

Okta Threat Intelligence 介绍过一个 AI 视频服务,其免费试用吸引了大量虚假注册尝试。在一位客户的日志里,“2026 年 6 月 1 日至 7 月 1 日之间,日志显示来自 251 个不同 IP(可能与机器人相关)的暴力注册尝试超过 105,000 次”。这些注册“与代理服务商和 VPN 有关”。按 GeoIPHub 对 Okta 数字的计算,这相当于整个月平均每个地址约 418 次尝试,或每天约 14 次,所以“每个 IP 每小时几次注册”的限制可能永远不会触发。
难点在于虚假注册与真实客户共用相同的网络。真实的人也会使用 VPN 和云桌面,而真实的人共用的地址,比如 iCloud Private Relay、移动运营商和运营商级 NAT,天生就显得很繁忙。只做拦截的规则,要么放进整个团伙,要么把客户拒之门外。
下文内容包括:注册可能来自的七个地址、GeoIPHub 的 IP 查询 API 在 2026 年 11 月 2 日对每个地址返回了什么,以及我们会在表单上怎么处理;为什么绝不能仅凭评分拒绝共享地址;带有经过测试的代码的频次限制;以及 IP 看不到的东西。

虚假账户检测在注册时检查什么,以及您始终拥有的那个信号
虚假账户检测会在网络、频次、邮箱、手机、设备和行为这几个方面为每次新注册评分。在表单提交的那一刻,IP 是其中唯一一个您的服务器无需向用户索取任何东西就始终拥有的,这就是为什么 IP 欺诈评分通常是第一道检查。
OWASP 把这种攻击命名为 OAT-019 Account Creation:“利用应用程序的账户注册流程批量创建账户,有时还会填充个人资料。”创建虚假账户很少是最终目的;它是为促销与推荐刷取、为一个操作者躲避封禁而背后运营多个账户,或为布置凭证填充攻击所做的铺垫。
注册欺诈很常见,值得提前规划。Okta 的2025 年客户身份趋势报告基于其 Auth0 平台的数据,其中写道:“2024 年,Auth0 平台上所有注册尝试中,平均有 46% 被识别为注册攻击。”Stripe 在 2026 年 4 月 29 日发布 Sessions 2026 时,这样描述自家网络的数字:“在 Stripe 上运行的各类 AI 服务中,每六次注册尝试就有一次是恶意行为者发起的。”
下面是每一层的需求,以及其中哪些 IP 查询能够回答:
| 层 | 示例 | IP 查询能看到吗? |
|---|---|---|
| 网络 | Tor 出口、VPN 服务器、云服务器、中继、移动运营商 | 能 |
| 频次 | 一小时或一天内按地址、前缀或网络统计的注册次数 | 只能提供键;计数由您的代码完成 |
| 邮箱 | 一次性邮箱域名、加号地址和点号变体 | 不能 |
| 手机 | VoIP 号码、被回收的号码 | 不能 |
| 设备 | 在多个账户间重复出现的浏览器和硬件特征 | 不能;参见设备指纹 |
| 行为 | 表单填写速度、复制粘贴、鼠标移动 | 不能 |
设备这一行是另一种工具;我们对设备指纹和 IP 数据的比较讲解了两者如何结合。
七个注册 IP,七个决定:GeoIPHub 在 2026 年 11 月 2 日返回了什么
GeoIPHub 在 2026 年 11 月 2 日 UTC 04:51 到 04:52 之间查询了注册可能来自的七个地址。下面是评分、原因,以及我们会在表单上怎么处理,使用的是 GeoIPHub 的起步欺诈评分阈值中的注册那一行。最后两行是我们评分配置中的规则,而不是查询结果。
| 地址 | 它是什么 | 评分,操作 | detection_methods | 注册时 |
|---|---|---|---|---|
| 185.220.101.1 | Tor 出口,同时列入 zen.spamhaus.org | 100,block | tor_exit, datacenter_blocklisted, no_ptr_datacenter, known_spammer | 拒绝 |
| 185.213.155.73 | VPN 服务器;vpn_provider 指向 Mullvad | 100,block | known_vpn_server, wireguard_open, datacenter_with_vpn_proxy, no_ptr_datacenter | 默认拒绝;如果您的用户使用 VPN 且没有触发滥用原因,则改为验证 |
| 45.83.220.7 | Mullvad VPN 网络地址,vpn_provider 为 "Mullvad (31173 Services)" | 46,review | known_vpn_server, datacenter_ip | 创建,限制,标记 |
| 45.33.32.156 | scanme.nmap.org,一台 Linode 云服务器 | 10,allow | datacenter_ip | 放行;按托管网络计数 |
| 104.28.46.99 | iCloud Private Relay 出口 | 9,allow | relay_ip | 放行;更宽松的频次限制 |
| 66.249.66.1 | 已验证的 Googlebot(crawler.operator 为 Google) | 0,allow | datacenter_ip, verified_crawler | 不创建账户:爬虫不会注册 |
| 162.142.125.10 | Censys 互联网扫描器(is_scanner 为 true) | 0,allow | 没有返回原因 | 不创建账户 |
| 任意 CGNAT 地址 | 来自我们评分配置的规则,不是查询结果 | 上限为 50 | 只有当该地址自身有 VPN、代理、Tor、协议、僵尸网络或滥用证据时,上限才会解除 | 绝不仅凭评分拒绝 |
| 任意移动运营商地址 | 来自我们评分配置的规则,不是查询结果 | 降低 12 | mobile_carrier,前提是没有威胁证据 | 绝不仅凭评分拒绝 |
两个 100 分看起来一样,其实不同。Tor 出口带有垃圾邮件历史;VPN 服务器只带有匿名性方面的原因,完全没有滥用证据。这个差别决定了 VPN 注册是被拒绝还是被验证。
API 自己的 recommended_action 只有在高于 75 时才会给出 block。GeoIPHub 起步的注册阈值从 71 开始拦截,而 2026 年 11 月 2 日没有任何一行落在这两条线之间。
家庭宽带没有对应的行,因为我们不公布家庭用户的地址。GeoIPHub 的评分只有在地址具有住宅模式的反向 DNS 名称时,才会给家庭线路折扣,所以没有这种名称的家庭线路得不到住宅折扣,任何威胁原因都会全额计入。
读原因,而不是读数字:完整追踪一次注册
评分告诉您一个地址有多危险;scoring.detection_methods 告诉您原因,而原因决定了是限制、验证还是拒绝。下面是 45.83.220.7 的精简响应,查询时间是 2026 年 11 月 2 日 UTC 04:51:58:
{
"ip": "45.83.220.7",
"asn": {
"asn": 39351,
"org": "ESAB-AS - 31173 Services AB",
"connection_type": "datacenter"
},
"detection": {
"is_vpn": true,
"is_hosting": true,
"is_relay": false,
"is_mobile": false,
"vpn_provider": "Mullvad (31173 Services)"
},
"threat": { "is_cgnat": false },
"scoring": {
"fraud_score": 46,
"recommended_action": "review",
"detection_methods": ["known_vpn_server", "datacenter_ip"]
}
}
触发了两个原因。known_vpn_server 加 36 分(置信度 0.9 下的 40 分),datacenter_ip 加 10 分(0.5 下的 20 分),所以评分是 46。这落在 GeoIPHub 起步注册阈值的 26 到 50 区间:创建并标记。我们会以受限状态创建账户,在邮箱确认之前不给试用额度或奖励。由于 detection.is_hosting 为 true,这次注册还会在下面的频次检查中计入 AS39351。在第一个价值事件(比如开始试用或发放额度)时,请再次查询该 IP。
185.213.155.73 的 Mullvad 服务器评分 100 block,它的四个原因全部关乎匿名性,而不是滥用。注册时的默认做法是拒绝它。真实用户会使用 VPN 的产品,可以针对原因而不是原始数字编写规则,把这样的 100 分(有匿名性原因而没有滥用原因)送去邮件或手机验证。仅仅 VPN 是一种隐私选择,而它所保护的人往往正是被错误标记的人。带有垃圾邮件历史的 Tor 出口无论如何都保持拒绝。
0 分不等于通过:您注册表单上的爬虫与扫描器
在 GeoIPHub 2026 年 11 月 2 日的查询中,两个最“友好”的结果,即 66.249.66.1 上经过验证的 Googlebot 和 162.142.125.10 上的 Censys 扫描器,评分都是 0 allow,而它们恰恰是绝不应该创建账户的两个。这比任何一个 100 分都更让我们意外。
GeoIPHub 的 verified_crawler 原因会减去 28.5 分,所以已验证的爬虫落在评分刻度的最底端。对于抓取来说这是对的,对于表单 POST 来说则是错的。如果注册请求上的 threat.crawler.verified 为 true,就不要创建账户。判断时请读取 crawler.verified 和 crawler.operator,不要用 crawler.name。
threat.is_scanner 根本不参与评分:Censys 地址没有返回任何原因。请直接检查这个标记,为 true 时拒绝注册。
绝不仅凭评分拒绝共享地址:中继、CGNAT 和移动
iCloud Private Relay 出口、运营商级 NAT 地址或移动网关可能承载着许多真实的人。GeoIPHub 的评分把中继地址的上限设为 60,把 CGNAT 地址的上限设为 50(除非该地址自带威胁证据),并对干净的移动地址给予折扣,而带有威胁证据的移动地址反而会被扣分。除非这些地址自带证据,否则您的规则应当让它们远离拦截区间。
在 GeoIPHub 的评分中,relay_ip 加 8.5 分,且没有中继折扣,所以我们的中继样本评分为 9。CGNAT 的上限只有在该地址自身有 VPN、代理、Tor、协议、僵尸网络或滥用证据时才会解除。移动运营商地址会得到 mobile_carrier,在没有威胁证据时使评分降低 12。
这一切并不意味着“信任”。它的意思是,单靠 IP 无法把一个坏人与同一地址背后的众多客户区分开来。所以对这些注册要发起挑战,绝不仅凭评分拒绝,并给予十倍于常规的频次限制。具体到 Private Relay,建议是放行它们,并根据账户接下来的行为对会话评分。
在您自己的代码中按 IP、/24、IPv6 /64 和托管网络统计注册次数
GeoIPHub 的 API 对单个地址评分;它不会统计这个地址、它的 /24、它的 /64 或它的网络在过去 24 小时内创建了多少账户。这个计数器存在于您的代码里,而查询会告诉您该用哪些键:asn.asn、detection.is_hosting、detection.is_relay、detection.is_mobile、asn.connection_type 和 threat.is_cgnat。
在 Okta 的 AI 视频案例中,虚假注册尝试平均每个地址每天约 14 次,分散在 251 个地址上。单靠按 IP 的计数器可能永远不会触发。前缀和网络计数器正是为这种情况而设。
这些是我们选定的起点,不是行业基准;请根据您自己的注册数据调整。
| 键 | 时间窗口 | 起步限制 | 说明 |
|---|---|---|---|
| 精确的 IPv4 地址 | 1 小时 | 3 | |
| IPv4 /24 | 1 小时 | 10 | 抓住在同一网段内轮换的地址池 |
| IPv6 /64 | 1 小时 | 3 | 把一个 /64 当作一个 IPv4 地址;当同一个分配段不断冒出新的 /64 时,放宽到 /56 或 /48 |
| ASN,仅托管(detection.is_hosting 为 true) | 24 小时 | 20 | 真实客户很少从云服务器注册 |
| 共享地址(中继、CGNAT 或移动) | 相同窗口 | IP 与前缀限制的十倍 | 绝不仅凭频次拦截 |
超过限制意味着升级验证(邮件或手机验证,或 CAPTCHA)或受限创建,而不是拒绝。在 IPv6 上,统计前缀,永远不要统计完整地址,否则一个行为人会变成成千上万个“不同的”注册。家庭通常会分到 /56 或 /48,这就是表格中放宽的原因;我们的指南按前缀对 IPv6 限速介绍了各种分配规模。
下面的代码在 Node 18 或更高版本上运行,无需任何依赖。它期望客户端地址采用 Node 报告的形式(包括 ::ffff:192.0.2.1 这类 IPv4 映射形式),并且是在您从可信代理链中取得之后传入。它使用固定窗口,这是对滑动窗口的简化。
// Signup velocity keys: exact IP, IPv4 /24, IPv6 /64, and ASN for hosting.
// Starting limits, not benchmarks. Tune them on your own signups.
import { isIPv4, isIPv6 } from "node:net";
const HOUR = 3600e3, DAY = 24 * HOUR;
const LIMITS = {
ip: { window: HOUR, max: 3 }, // one IPv4 address, or one IPv6 /64
v4_24: { window: HOUR, max: 10 },
asn: { window: DAY, max: 20 }, // hosting networks only
};
const SHARED_FACTOR = 10; // relay, CGNAT and mobile egress
function expandIPv6(addr) {
const [head, tail = ""] = addr.toLowerCase().split("::");
const h = head ? head.split(":") : [];
const t = tail ? tail.split(":") : [];
const fill = addr.includes("::") ? 8 - h.length - t.length : 0;
return [...h, ...Array(fill).fill("0"), ...t].map((g) => g.padStart(4, "0"));
}
export function velocityKeys(ip, lookup) {
const keys = [];
const m = ip.match(/^(?:::|(?:0{1,4}:){5})ffff:(\d+\.\d+\.\d+\.\d+)$/i);
const v4 = m && isIPv4(m[1]) ? m[1] : ip;
if (isIPv4(v4)) {
keys.push(["ip", v4], ["v4_24", v4.split(".").slice(0, 3).join(".") + ".0/24"]);
} else if (isIPv6(ip)) {
keys.push(["ip", expandIPv6(ip).slice(0, 4).join(":") + "::/64"]);
}
const asn = lookup?.asn;
if (lookup?.detection?.is_hosting && asn?.asn) keys.push(["asn", `AS${asn.asn}`]);
return keys;
}
const counters = new Map(); // in-memory and unbounded; for a demo only; use Redis INCR + EXPIRE in production
export function checkVelocity(ip, lookup, now = Date.now()) {
const shared = Boolean(
lookup?.detection?.is_relay || lookup?.threat?.is_cgnat ||
lookup?.detection?.is_mobile || lookup?.asn?.connection_type === "mobile");
const hits = [];
for (const [level, value] of velocityKeys(ip, lookup)) {
const { window, max } = LIMITS[level];
const limit = shared && level !== "asn" ? max * SHARED_FACTOR : max;
const key = `${level}:${value}:${Math.floor(now / window)}`;
const count = (counters.get(key) ?? 0) + 1;
counters.set(key, count);
if (count > limit) hits.push({ level, value, count, limit });
}
return { overLimit: hits.length > 0, hits }; // over the limit: step up, don't block
}
我们在 2026 年 11 月 2 日于 Node 24.20.0 下,对这段代码做了 16 项单元测试,使用的是文档用地址段、私有地址段以及表中的 scanme.nmap.org 地址,没有进行任何查询。16 项全部通过:::ffff:45.33.32.156 这类 IPv4 映射形式被按 IPv4 取键;在同一个 /64 内轮换时,第 4 次注册触发限制;一个 /24 内的 11 个地址只触发了 /24 这个键;来自同一个中继出口的 30 次注册通过,而第 31 次被标记。查询失败(null)时仍然会生成 IP 和前缀这两个键,所以 API 没有响应时计数器照常工作。
IP 层在哪里失明
IP 查询看不到从租用的家庭连接或真实手机注册的虚假账户,也永远看不到邮箱、设备或表单是如何填写的。
住宅代理是最明显的缺口。GeoIPHub 会标记我们在住宅和移动线路上观察到的代理,包括第三方名单报告为中继的地址,但我们自己没有住宅代理检测,一条干净的家庭线路可以通过。运行在真实 SIM 卡上的点击农场和设备农场看起来就像移动客户,而我们的评分有意对移动客户比较宽容。
GeoIPHub 对 IP 评分;它不检查邮箱地址或手机号码。请把 IP 检查与您自己的邮箱检查(一次性邮箱域名、加号地址和点号归一化)、手机验证、设备信号,以及注册之后对共用键的账户进行聚类结合起来。
受限状态是让中间区间运行成本低廉的关键。创建账户,扣留额度,并在验证之后或第一次真实操作之后释放。一个从未验证的虚假账户,让您付出的只是数据库里的一行,而不是一次试用。
如何在账户出现之前阻止虚假注册
整个检查就是在“提交”与“创建”之间做一次查询和一次频次统计,顺序如下:
- 从您可信的代理链中获取客户端 IP,而不是直接读取原始的
X-Forwarded-For请求头,因为客户端可以把它设成任何值。 - 查询该 IP。
- 拒绝 Tor 出口、已验证的爬虫和扫描器。默认拒绝评分 100 的 VPN 服务器,或者如果您的用户使用 VPN 且没有触发滥用原因,就送去验证。绝不仅凭评分拒绝中继、CGNAT 或移动地址。对其他一切应用 GeoIPHub 的起步注册阈值。
- 运行频次检查,命中时升级验证。
- 如果查询失败,回退到频次检查和邮箱确认;不要拒绝。
- 把评分、原因和查询时间与账户一起存储,并在第一个价值事件(开始试用、发放额度、首次提现)时再次查询该 IP。
我们经过测试的 Node 和 Python 集成以可运行代码展示了第 2 步和第 3 步。GeoIPHub 的免费套餐每天涵盖 1,500 次查询,包含所有字段。
把您注册日志中最近的十个 IP 粘贴到 IP 欺诈评分检查器,并把它们归入表中的各行。评分告诉您每个地址是什么;计数器告诉您它创建了多少账户。
常见问题
如何在不拦截真实用户的前提下阻止虚假注册?
在创建账户之前,用 GeoIPHub 的 API 查询每次注册的 IP。拒绝 Tor 出口和最高分的地址,对中间区间通过邮件或手机验证,而像 iCloud Private Relay、运营商级 NAT 和移动网关这样的共享地址则以更宽松的频次限制放行,因为这类地址中的一个可能承载着许多真实客户。
注册欺诈有多常见?
在 Okta 的 Auth0 平台上,2024 年平均有 46% 的注册尝试被识别为注册攻击。Stripe 在 2026 年 4 月表示,其网络上各类 AI 服务的注册尝试中,每六次就有一次是恶意行为者发起的。这两个数字都是厂商基于自家平台给出的数据。
仅凭 IP 地址就能检测虚假账户吗?
不能。IP 查询能显示注册来自哪种网络以及评分的原因,但看不到邮箱、手机号、设备,也看不到从租用的家庭连接注册的虚假账户。请把它作为第一层,并与邮箱、手机和设备检查搭配使用。
GeoIPHub 会检查邮箱地址吗?
不会。GeoIPHub 的 API 只对 IP 地址评分。请用您自己的工具检查邮箱和手机号,并把结果与 GeoIPHub 的评分和原因结合起来。
应该允许 VPN 用户注册吗?
通常可以。VPN 本身只是一种隐私选择,所以您可以把 VPN 注册送去邮件或手机验证而不是拒绝,把直接拦截留给 Tor 出口和有垃圾邮件或滥用历史的地址。
如何对 IPv6 上的注册限速?
按 /64 计数,而不是按单个地址,因为一个订阅用户可以在整个 /64 内轮换地址。当同一个分配段不断冒出新的 /64 时,放宽到 /56 或 /48,并对移动运营商保持更宽松的限制。
GeoIPHub API 背后的团队
由 GeoIPHub 团队撰写,即构建 GeoIPHub IP 情报 API 及其扫描器的团队。草稿在 AI 辅助下完成,并由团队编辑;除非标注为示例,API 示例均为针对线上 API 的真实查询。


