如何用 PHP 识别 reCAPTCHA v3 并设置 action

solve recaptcha v3 in php - How to Solve reCAPTCHA v3 in PHP and Set an Action

reCAPTCHA v3 从不渲染挑战。它会悄悄为访问评分,并给页面一个 token,随后由网站后端进行验证。从代码角度看,这意味着没有任何需要点击的东西,因此整个任务就是生成一个网站会接受的 token。在 PHP 中,这与你用于 v2 的 recaptcha 方法相同,只是在选项数组中加了一个版本标志。

决定它能否成功的关键是 action。

设置

# PHP 8.0+, with the curl and json extensions.
composer require capskip/capskip
use CapSkip\CapSkip;

$solver = new CapSkip([
    'host' => '127.0.0.1',
    'port' => 8080,
    'recaptchaTimeout' => 300,   // seconds, shared with Turnstile and GeeTest
]);

CapSkip 在你自己的机器上运行,因此必须先打开桌面应用。

基本调用

$result = $solver->recaptcha(
    '6Lc...YOUR_SITEKEY',
    'https://example.com/checkout',
    [
        'version' => 'v3',
        'action' => 'submit',
    ]
);

echo $result['code'];   // the v3 token

与 v2 有两点不同。 version 必须为 v3,以及 action 应与页面传给 grecaptcha.execute的值一致。若省略,则默认为 verify.

为什么 action 很重要

action 是网站为每个受保护交互附加的标签,这样登录和结账就能被分别评分。大多数后端会检查 token 携带的 action 是否与该端点所预期的一致。

如果发送了错误的标签,token 虽然真实,但会被标记为另一个交互,许多验证程序会直接拒绝。请从页面读取真实值,而不要猜测:

$html = file_get_contents('https://example.com/checkout');

// Sites normally call execute() with the action as a string literal.
preg_match('/execute\([^,]+,\s*\{\s*action:\s*[\'"]([^\'"]+)/', $html, $m);
$action = $m[1] ?? 'verify';

$result = $solver->recaptcha($sitekey, $pageUrl, [
    'version' => 'v3',
    'action' => $action,
]);

常见的值有 login, submit, homepagecheckout,但它们只是网站构建者随意选定的字符串。

Enterprise v3

$result = $solver->recaptcha($sitekey, $pageUrl, [
    'version' => 'v3',
    'enterprise' => 1,
    'action' => 'submit',
]);

Enterprise 是一个正交的标志,而不是一款独立产品,因此它叠加在 v3 调用之上。可通过页面加载的脚本来区分:Enterprise 加载的是 enterprise.js,而标准版加载的是 api.js。猜错只会导致识别失败,而不会返回错误的 token,因此测试起来毫无代价。

提交 token

$ch = curl_init('https://example.com/checkout');

curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => json_encode([
        'token' => $result['code'],
        'order_id' => '...',
    ]),
]);

$response = curl_exec($ch);
curl_close($ch);

与 v2 不同,没有标准的表单小组件来约束其形式,因此 v3 的集成方式各不相同。有些使用隐藏的 g-recaptcha-response 输入框,有些则以自定义键提交 JSON。在假定字段名之前,请先查看页面自身的 JavaScript。

错误

use CapSkip\Exceptions\ApiException;
use CapSkip\Exceptions\NetworkException;
use CapSkip\Exceptions\TimeoutException;

try {
    $result = $solver->recaptcha($sitekey, $pageUrl, ['version' => 'v3']);
} catch (NetworkException $e) {
    // CapSkip is not running on the configured port
} catch (ApiException $e) {
    // the sitekey or pageurl was rejected
} catch (TimeoutException $e) {
    // exceeded recaptchaTimeout
}

同样要注意其中的 CapSkip\Exceptions 命名空间。从 Python 或 Node 示例中照搬 import 语句,是这里致命错误的常见来源。

常见问题

我能在提交前查看分数吗?

不能。分数保存在 Google 手中,只有当网站所有者的后端验证 token 时才会向其披露。在客户端你只会收到一个 token,别无其他,因此事先没有任何可查看或筛选的内容。

我应该在 Web 请求内部进行识别吗?

最好不要。PHP 是同步的,一次识别可能耗时数秒,因此在页面渲染期间执行会在此期间占用一个工作进程。请将其移入队列任务或 CLI 工作进程。

如果页面从不设置 action 怎么办?

有些页面调用 execute 时不带 action,这种情况下默认值 verify 是正确的。如果你的正则表达式没有找到任何内容,通常正是这个原因,而不是解析错误。

小结

设置 version 设置为 v3,让 action 与页面执行的值匹配,添加 enterprise (当页面加载它时) enterprise.js,从以下模块导入异常: CapSkip\Exceptions,并尽快提交 token,因为它大约两分钟后就会过期。

其他语言在 reCAPTCHA v3 识别工具 页面介绍,Enterprise 的详情在 Enterprise 识别工具 页面介绍,更广泛的 PHP 接口在 PHP 验证码识别 页面介绍。你可以在我们的 v3 演示上进行实验。CapSkip 采用 验证码识别工具 ,它运行在你自己的硬件上。