reCAPTCHA Enterprise 升级的是服务端那份评估报告,不是用户看到的验证码。站点运营方调评估 API 能读到分数、原因码和账号标签;自动化侧收到的仍旧只是一串 token,集成流程不必重写。把这条界线画清楚,分数为什么停在 0.1、token 明明有效却被拦,就都有了排查方向。
Enterprise 评估 API 的完整链路
前端只负责产出 token,判断发生在服务端:
Client-side:
1. Load reCAPTCHA Enterprise script
2. Call grecaptcha.enterprise.execute(SITE_KEY, {action: 'LOGIN'})
3. Receive token
4. Send token to your backend
Server-side:
1. Create assessment via Enterprise API
2. Receive detailed risk analysis
3. Make access decision based on score + reasons
4. Optionally annotate the assessment (report fraud/legitimate)
token 本身不带分数——它在服务端换评估结果时才生成,同一串 token 在不同站点、不同 action 下结论可能完全不同。
reCAPTCHA Enterprise 与标准 v3 有哪些实际差别
多出来的能力集中在服务端:
| 对比项 | reCAPTCHA v3(免费) | reCAPTCHA Enterprise |
|---|---|---|
| 评分 | 0.0–1.0 分 | 0.0–1.0 分 + 分数原因 |
| 风险分析 | 基础 | 详细(欺诈信号、账号信息) |
| 分数原因 | 不提供 | 给出具体原因码 |
| Account Defender | 无 | 有(跟踪账号生命周期) |
| WAF 集成 | 无 | 有(Cloudflare、Fastly、F5) |
| 快速评估 | 无 | 有(纯服务端,不需要 JS) |
| 密码泄露检测 | 无 | 有 |
| 定价 | 免费(每月 100 万次评估) | 每 1000 次评估 $1(前 100 万次免费) |
| API 接口 | google.com/recaptcha/api/siteverify | recaptchaenterprise.googleapis.com |
国内团队碰到 Enterprise 多半是在出海业务上:本土站点常用极验(GeeTest)、腾讯防水墙,海外 SaaS 的注册登录页才大量出现 Enterprise。
前端接入:enterprise.js 与 grecaptcha.enterprise
JavaScript SDK 的写法
<script src="https://www.google.com/recaptcha/enterprise.js?render=SITE_KEY"></script>
<script>
grecaptcha.enterprise.ready(function() {
grecaptcha.enterprise.execute('SITE_KEY', { action: 'LOGIN' })
.then(function(token) {
// Send token to backend
fetch('/api/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token: token })
});
});
});
</script>
与标准 v3 相比只有三处不同:
- 脚本地址是
.../recaptcha/enterprise.js,不是.../recaptcha/api.js - 调用对象是
grecaptcha.enterprise,不是grecaptcha execute()返回的 token 格式完全一样
从页面源码判断版本
不用开发者工具,抓一次 HTML 就够:
import requests
import re
def detect_recaptcha_enterprise(url):
"""Detect if a page uses reCAPTCHA Enterprise."""
html = requests.get(url, timeout=10).text
indicators = {
"is_enterprise": False,
"is_standard": False,
"site_key": None,
"actions": [],
}
# Enterprise detection
if "recaptcha/enterprise.js" in html:
indicators["is_enterprise"] = True
match = re.search(r"render=([A-Za-z0-9_-]+)", html)
if match:
indicators["site_key"] = match.group(1)
# Standard v3 detection
elif "recaptcha/api.js?render=" in html:
indicators["is_standard"] = True
match = re.search(r"render=([A-Za-z0-9_-]+)", html)
if match:
indicators["site_key"] = match.group(1)
# Extract action names
actions = re.findall(r"action:\s*['\"](\w+)['\"]", html)
indicators["actions"] = list(set(actions))
return indicators
print(detect_recaptcha_enterprise("https://staging.example.com/qa-login"))
actions 一并抽出来是有意为之,它必须与站点实际发送的值一致。依赖装不上时走国内镜像:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple requests。
服务端:调用评估 API 创建 assessment
这一节属于站点运营方:需要 Google Cloud 项目与权限,仅测试自有集成时用得上。
创建评估
from google.cloud import recaptchaenterprise_v1
from google.cloud.recaptchaenterprise_v1 import Assessment
def create_assessment(project_id, site_key, token, action):
"""Create a reCAPTCHA Enterprise assessment."""
client = recaptchaenterprise_v1.RecaptchaEnterpriseServiceClient()
event = recaptchaenterprise_v1.Event()
event.site_key = site_key
event.token = token
event.expected_action = action
assessment = recaptchaenterprise_v1.Assessment()
assessment.event = event
request = recaptchaenterprise_v1.CreateAssessmentRequest()
request.assessment = assessment
request.parent = f"projects/{project_id}"
response = client.create_assessment(request)
return response
评估响应的结构
{
"name": "projects/123456/assessments/abcdef123",
"event": {
"token": "...",
"siteKey": "6Le...",
"expectedAction": "LOGIN",
"hashedAccountId": "abc123..."
},
"riskAnalysis": {
"score": 0.9,
"reasons": [
"AUTOMATION",
"TOO_MUCH_TRAFFIC"
],
"extendedVerdictReasons": [
"BROWSER_ERROR"
]
},
"tokenProperties": {
"valid": true,
"hostname": "example.com",
"action": "LOGIN",
"createTime": "2025-01-15T10:30:00Z",
"invalidReason": ""
},
"accountDefenderAssessment": {
"labels": ["PROFILE_MATCH"]
}
}
三个字段最值得看:
riskAnalysis.score— 0.0 到 1.0,越低越可疑riskAnalysis.reasons— 分数为什么低,Enterprise 独有tokenProperties.valid— 返回false时先看invalidReason,多半是过期或域名不符
Account Defender:账号维度的风险标签
Account Defender 把判断从单次请求扩展到账号的整个生命周期:
{
"accountDefenderAssessment": {
"labels": [
"PROFILE_MATCH",
"SUSPICIOUS_LOGIN_ACTIVITY",
"SUSPICIOUS_ACCOUNT_CREATION",
"RELATED_ACCOUNTS_NUMBER_HIGH"
]
}
}
| 标签 | 含义 |
|---|---|
PROFILE_MATCH |
行为与该账号的已知画像一致 |
SUSPICIOUS_LOGIN_ACTIVITY |
登录模式异常(新设备、新地区) |
SUSPICIOUS_ACCOUNT_CREATION |
注册行为看起来是自动化的 |
RELATED_ACCOUNTS_NUMBER_HIGH |
多个账号关联到同一设备或会话 |
这些标签只对站点运营方可见,且要传 hashedAccountId 才会产生。
读懂分数原因:reasons 字段说明了什么
| 原因码 | 说明 | 分数影响 |
|---|---|---|
AUTOMATION |
检测到自动化 user agent 或无头浏览器 | -0.3 至 -0.7 |
UNEXPECTED_ENVIRONMENT |
浏览器或设备环境不一致 | -0.2 至 -0.4 |
TOO_MUCH_TRAFFIC |
同一 IP 或会话请求量过高 | -0.1 至 -0.3 |
UNEXPECTED_USAGE_PATTERNS |
行为信号偏离常见人类模式 | -0.2 至 -0.5 |
LOW_CONFIDENCE_SCORE |
数据不足,无法给出可信判断 | 不固定 |
SUSPECTED_CARDING |
交易模式接近信用卡欺诈特征 | -0.3 至 -0.6 |
SUSPECTED_CHARGEBACK |
基于交易信号判断的拒付风险 | -0.2 至 -0.4 |
分数影响为量级参考,并非 Google 公布的固定权重,请以自有环境观测为准。
扩展判定原因(extendedVerdictReasons)
| 原因码 | 说明 |
|---|---|
BROWSER_ERROR |
验证码 SDK 里的 JavaScript 执行报错 |
SITE_MISMATCH |
token 是为另一个站点生成的 |
FAILED_TWO_FACTOR |
近期有双因素认证失败记录 |
SITE_MISMATCH 最容易踩:pageurl 写得不准,token 就会被打上这个标记。
WAF 边缘集成:Cloudflare 与 F5 BIG-IP
Enterprise 也能挂在 WAF 上,让挑战发生在到达源站之前:
Cloudflare WAF
Request arrives at Cloudflare edge
↓
Cloudflare WAF rule evaluates request
↓
Rule triggers reCAPTCHA Enterprise challenge
↓
Client solves CAPTCHA → token returned
↓
Cloudflare validates token via Enterprise API
↓
If valid + score above threshold → request forwarded to origin
F5 BIG-IP
F5 iRule or policy evaluates request
↓
Triggers reCAPTCHA Enterprise challenge page
↓
Client solves → token validated server-side
↓
F5 forwards or blocks based on assessment score
这类部署要先过挑战页才看到表单,pageurl 应填承载挑战的那个地址。
自动化场景:用 CaptchaAI 识别 reCAPTCHA Enterprise
求解侧把 Enterprise 当同一种 token 处理:方法名仍是 userrecaptcha,只多传一个标志位。
Python
import requests
import time
API_KEY = "YOUR_API_KEY"
# Enterprise is solved with the same method
# The solver handles the Enterprise variant automatically
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": "6LcR_RsTAAAAAN_r0GEkGBfq3L7KmU5JbPHJtwNp",
"pageurl": "https://enterprise-site.com/login",
"enterprise": 1, # Flag for Enterprise variant
"json": 1,
})
task_id = submit.json()["request"]
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "get",
"id": task_id,
"json": 1,
}).json()
if result.get("status") == 1:
token = result["request"]
print(f"Enterprise token: {token[:50]}...")
break
Node.js
const axios = require("axios");
async function solveEnterprise(sitekey, pageurl) {
const API_KEY = "YOUR_API_KEY";
const { data: submit } = await axios.post(
"https://ocr.captchaai.com/in.php",
new URLSearchParams({
key: API_KEY,
method: "userrecaptcha",
googlekey: sitekey,
pageurl: pageurl,
enterprise: 1,
json: 1,
})
);
const taskId = submit.request;
for (let i = 0; i < 60; i++) {
await new Promise(r => setTimeout(r, 5000));
const { data: result } = await axios.get(
"https://ocr.captchaai.com/res.php",
{ params: { key: API_KEY, action: "get", id: taskId, json: 1 } }
);
if (result.status === 1) return result.request;
}
throw new Error("Timeout");
}
把版本判断收敛成一个函数
写死版本迟早出问题——站点升级到 Enterprise 不会通知你:
def identify_recaptcha_version(html):
"""Determine which reCAPTCHA version a page uses."""
if "recaptcha/enterprise.js" in html:
return "enterprise"
elif "recaptcha/api.js?render=" in html:
return "v3"
elif "g-recaptcha" in html and 'data-size="invisible"' in html:
return "v2_invisible"
elif "g-recaptcha" in html:
return "v2"
else:
return "none"
CaptchaAI 按线程计费,不按次计费:BASIC $15/月 5 线程、STANDARD $30/月 15 线程、ADVANCE $90/月 50 线程,套餐内识别次数不限,Enterprise 不加价。
reCAPTCHA Enterprise 排错对照表
| 现象 | 原因 | 处理方式 |
|---|---|---|
| Enterprise 站点提交后 token 被拒 | 用标准方法提交了 Enterprise 页面 | 请求里补上 enterprise=1 |
| token 有效,分数却长期停在 0.1 | action 与页面发送的值不一致 |
逐字核对页面里的 action |
reasons 里出现 AUTOMATION |
站点判定运行环境为自动化 | CaptchaAI 侧会处理,持续出现请联系支持 |
| token 校验通过,请求仍被拦 | 站点还有验证码之外的检查 | 排查 WAF 规则、限流等风控层 |
常见问题
CaptchaAI 支持 reCAPTCHA Enterprise 吗?怎么计费?
支持,v2 Enterprise 与 v3 Enterprise 都在正式支持范围内,用 userrecaptcha 加 enterprise=1 提交即可。计费按线程算,BASIC $15/月 5 线程,识别次数不限。
在第三方站点上,我能看到分数和原因码吗?
看不到。riskAnalysis 只有站点运营方调评估 API 才拿得到,求解侧只收到 token。只有测自己的集成时,才能把分数和 reasons 串起来看。
提交任务时漏了 enterprise=1 会怎样?
多数情况下仍会返回格式正确的 token,但站点校验不通过,看着很像“识别质量差”。判断标准很简单:页面加载 enterprise.js 就带,加载 api.js 就别带。
国内网络下调试 Enterprise 页面加载不出来,是集成写错了吗?
多半不是。前端脚本由 Google 域名提供,境内可达性不稳定,加载超时与 sitekey、action 无关。把复现环境放到境外服务器或 CI 上再跑一次即可确认。识别请求本身走 CaptchaAI 的接口,不受此影响。
用自动化处理验证码,合规上要注意什么?
只采集你有权采集的数据,并留意网络安全法、数据安全法、PIPL 以及目标站点的 robots 协议。技术跑得通不等于合规。
小结
Enterprise 补的全是服务端的“解释能力”,token 格式没变。自动化侧只需三件事:确认页面加载 enterprise.js、给 CaptchaAI 请求补上 enterprise=1、让 pageurl 与 action 对齐。