如何在 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, so .NET Framework 4.6.1+, Core 2.0+
# and every modern .NET release are all supported.
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 呢?

相同的方法,不同的选项。去掉 version 和 action,并添加 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 */ }

TimeoutException 和 ValidationException 在两个命名空间中都存在 System 和 CapSkip。同时导入两个命名空间时,未限定的 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 设置为 v3 和 enterprise 设置为 1,把 action 从页面上一字不差地复制下来,然后提交 result.Code ,务必在两分钟内完成。没有需要调整的分数,因此如果 token 被拒,请先检查 action 和这些标志。

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