如何在 C# 中识别 reCAPTCHA v3 Enterprise(.NET SDK)

recaptcha v3 enterprise in c# - How to Solve reCAPTCHA v3 Enterprise in C# (.NET SDK)

在 C# 中识别 reCAPTCHA v3 Enterprise 使用的方法与其他所有 reCAPTCHA 类型相同。没有 RecaptchaEnterpriseAsync。你要调用 RecaptchaAsync 并传入两个标志: version 设为 v3,以及 enterprise 设为 1。漏掉任何一个,你都会得到一个针对不同产品的 token,网站会拒绝它。

下面是完整的调用、 action 选项的实际作用,以及如何判断你面对的是哪种变体。

version 和 enterprise 是相互独立的标志

这一点几乎所有人第一次都会搞混。Enterprise 不是 reCAPTCHA 的第四个版本。它是 Google 的另一个产品层级,同时运行 v2 和 v3,因此这两个设置构成一个真正的 2×2 组合。

网站运行的类型你传入的选项
reCAPTCHA v2 复选框
reCAPTCHA v2 Enterpriseenterprise = 1
reCAPTCHA v3version = "v3"
reCAPTCHA v3 Enterpriseversion = "v3"enterprise = 1

单独传入 enterprise = 1 会让你得到一个 v2 Enterprise 的识别结果,它在 v3 页面上会失败。这是 token 返回正常却随后被拒绝的最常见原因。

如何判断页面是否为 Enterprise

打开页面源代码,查看脚本调用的是哪个对象。标准 reCAPTCHA 使用 grecaptcha。Enterprise 使用 grecaptcha.enterprise.

// Enterprise pages call grecaptcha.enterprise, not grecaptcha.
// The action name you need is right here in execute().
grecaptcha.enterprise.ready(function () {
  grecaptcha.enterprise.execute("YOUR_SITEKEY", { action: "login" })
    .then(function (token) {
      // token gets posted with the form
    });
});

还有两个迹象:脚本标签加载 /recaptcha/enterprise.js 而不是 /recaptcha/api.js,而 Enterprise 的 sitekey 通常以 6L 开头,和标准的一样,因此 key 本身说明不了什么。要相信脚本,而不是 key。

设置

CapSkip 在你自己的机器上运行,因此在这一切生效之前请先启动应用,然后从 NuGet 安装 SDK:

# .NET Standard 2.0,因此支持 .NET Framework 4.6.1+、Core 2.0+
# 以及所有现代 .NET 版本。
dotnet add package CapSkip

将客户端指向应用中显示的端口:

using CapSkip;

var solver = new CapSkipClient(
    apiKey: "capskip",        // any string when key validation is off
    host: "127.0.0.1",
    port: 8080,
    recaptchaTimeout: 300);   // seconds; v3 rarely gets near this

v3 Enterprise 调用

除 sitekey 和 URL 之外的所有内容都放在一个选项字典中:

using System.Collections.Generic;
using CapSkip;

var result = await solver.RecaptchaAsync(
    "YOUR_SITEKEY",
    "https://example.com/page-with-recaptcha",
    new Dictionary<string, object?>
    {
        ["version"]    = "v3",
        ["enterprise"] = 1,
        ["action"]     = "login",   // match the page exactly
    });

Console.WriteLine(result.Code);   // g-recaptcha-response token

签名为 RecaptchaAsync(string sitekey, string url, Dictionary<string, object?>? options = null)。该字典的值可为 null,因此 object? 如果你的项目启用了可空引用类型,这一点很重要。

action 选项的实际作用

action 仅用于 v3。在 v2 页面上它不起任何作用。

它是页面传给 grecaptcha.enterprise.execute()的标签。Google 会分别为每个 action 打分,网站后端通常会检查验证响应中的 action 是否与预期一致。如果页面写的是 login 而你用默认值去识别,那么你的 token 虽然有效却仍会被丢弃。请一字不差地复制该字符串,包括大小写。Google 将 action 限制为字母数字、斜杠和下划线,因此没有什么特殊字符需要转义。

出错时是静默的。不会报任何错,因为识别一侧没有任何问题。你只会得到一个被端点拒绝的 token。

没有最低分数选项

有必要直说,因为有些识别 API 会以此为卖点:你无法要求 CapSkip 返回某个特定分数的 token。分数是 Google 的判断,在你的目标站点验证 token 时给出,识别请求上没有任何参数能为它设定下限。如果你见过某个 min_score 字段,并在这里寻找对应项,那这就是你找不到它的原因。

提交 token

token 会写入页面提交的字段,通常是 g-recaptcha-response:

using System.Net.Http;

using var http = new HttpClient();

var form = new FormUrlEncodedContent(new[]
{
    new KeyValuePair<string, string>(
        "g-recaptcha-response", result.Code),
    new KeyValuePair<string, string>("username", "demo"),
});

var response = await http.PostAsync(
    "https://example.com/login", form);

有一样东西你在这里不需要: result.UserAgent。它仅对 Turnstile 有值,对每一次 reCAPTCHA 识别都为 null。如果你从 Turnstile 代码复制了辅助函数,请去掉那个响应头,而不要发送 null。

reCAPTCHA token 同样是短命的。Google 会在两分钟后使其过期,因此请在你准备提交的那一刻识别,而不是在一长串工作流程的开头。

那 v2 Enterprise 呢?

相同的方法,不同的选项。去掉 versionaction,并添加 datas 如果 Google 给页面提供了一个 data-s 值:

var v2 = await solver.RecaptchaAsync(sitekey, pageUrl,
    new Dictionary<string, object?>
    {
        ["enterprise"] = 1,
        ["datas"]      = "YOUR_DATA_S_VALUE",
    });

data-s 出现在 Google 自家的产品上,几乎别无他处。如果你在页面中找不到它,就不需要它。

处理失败

每个 SDK 异常都派生自 CapSkipError。在编写 catch 块之前,有一个 .NET 陷阱值得了解。

using System;
using CapSkip;

try
{
    var result = await solver.RecaptchaAsync(sitekey, pageUrl, options);
}
catch (CapSkip.ValidationException) { /* bad parameters */ }
catch (NetworkException)            { /* CapSkip is not running */ }
catch (ApiException)                { /* API returned an error */ }
catch (CapSkip.TimeoutException)    { /* exceeded recaptchaTimeout */ }
catch (CapSkipError)                { /* anything else from the SDK */ }

TimeoutExceptionValidationException 在两个命名空间中都存在 SystemCapSkip。同时导入两个命名空间时,未限定的 catch 会解析为 System 类型,然后悄无声息地永不触发。请对它们加以限定,或者捕获 CapSkipError 并检查它。

常见错误

代码原因修复
ERROR_GOOGLEKEYSitekey 为空或格式错误请从实时页面重新读取,而不是从缓存副本读取
ERROR_PAGEURLURL 缺失或不是完整的绝对 URL请包含协议头(scheme),并使用小组件所在的页面
ERROR_BAD_PARAMETERS某个选项值的类型错误校验 enterprise 是数字 1,而不是字符串 “1”
ERROR_CAPTCHA_UNSOLVABLE识别未能完成请确认版本标志与页面一致,然后在相同的网络路径上添加代理

每种类型的完整参数列表见 API 文档.

常见问题

Enterprise 是否有单独的方法?

没有。 RecaptchaAsync 可处理全部四种组合。Enterprise 只是选项字典中的一个标志,它与 version 配合使用,而不是替代它。

如果我把 action 名称写错了会怎样?

你会得到一个完全有效但被网站拒绝的 token。Google 在验证时会将 action 与分数一并返回,大多数后端会将其与预期值进行比较。识别工具不会报错,因为识别端并没有出错。

v3 Enterprise 需要代理吗?

仅当网站对地理位置敏感,或分数取决于请求 IP 时才需要。传入 ["proxy"] = new Proxy("HTTPS", "user:[email protected]:3128") 到同一个选项字典中。reCAPTCHA、Turnstile 和极验(GeeTest)支持代理,但图片验证码不支持。

我可以一次识别多个页面吗?

可以。每个方法都会返回一个 Task,因此 await Task.WhenAll(...) 就是你所需要的全部。SDK 还导出了 AsyncCapSkip ,但在 .NET 中它只是 CapSkipClient的别名,保留它是为了让从 Python SDK 移植过来的代码仍能编译。它没有任何额外作用。

小结

一个方法,两个标志。设置 version 设置为 v3enterprise 设置为 1,把 action 从页面上一字不差地复制下来,然后提交 result.Code ,务必在两分钟内完成。没有需要调整的分数,因此如果 token 被拒,请先检查 action 和这些标志。

.NET 的其余接口见 C# 验证码识别 页面, Enterprise 支持 涵盖了其他语言,而 reCAPTCHA v3 识别 则更深入讲解评分。CapSkip 是一款 本地验证码识别工具,因此这里的每一次识别都在你自己的机器上完成。