如何实施Google reCAPTCHA [v2隐藏版本] [Laravel]


实施Google reCAPTCHA

由于机器人攻击,我们决定引入reCAPTCHA来响应大量应用程序,因此我们将描述该过程。

如果您不知道如何实现reCAPTCHA ..,则可能会有所帮助。

有v2和v3,但我想尽可能避免用户的应用程序,并采取最小的机器人对策,因此
在v2的隐藏版本中实现。

这次不涉及v2复选框和v3方法。

为了清楚起见,以PHP框架Laravel为例,但我认为可以以其他方式在其他框架和所谓的Vanilla PHP中实现。

环境假定为LAMP。

Google reCAPTCHA隐形设置程序

管理屏幕上的设置

首先,我们必须为每个站点发布一个API密钥,因此我们将在管理屏幕上进行设置。

访问Google reCAPTCHA网站。
https://www.google.com/recaptcha/intro/v3.html

Image201905211254.png

转到管理控制台并添加一个新站点,

Image201905211256.png

"标签"可以是您喜欢的任何名称。

"安全设置"具有3个级别,
当我将其设置为2到3时,有时用户的应用程序会被图像身份验证拒绝,因此
我们决定将其设置为一个"最小用户负担"的级别。

grc2.png

确认上述内容后,将发布API站点密钥和秘密密钥。

接下来,我们将在Laravel上进行设置。

JS标签

的安装

首先,加载API JS文件。
插入模板文件的<head>内部。

资源/视图/表单/input.blade.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        FooBar Form
+       <script src="https://www.google.com/recaptcha/api.js" async defer></script>
    </head>
    <body>
        // contents

        <form action="entry/input/" method="post" id="form">
            // form inputs
        </form>
    </body>
</html>

前标签脚本设置

设置配置

由于最好不要管理

API密钥的版本,因此请使用.env进行设置。
APP_RECAPTCHA_SITE_KEY是先前在管理屏幕上发布的站点的键,
APP_RECAPTCHA_SECRET_KEY是先前发布的密钥。

.env

1
2
+ APP_RECAPTCHA_SITE_KEY=your_site_key
+ APP_RECAPTCHA_SECRET_KEY=your_secret_key

读取设置的文件。
API端点也在此处设置。

config / app.php

1
2
3
4
5
6
7
8
9
10
11
12
    /*
    |--------------------------------------------------------------------------
    | reCAPTCHA Settings
    |--------------------------------------------------------------------------
    |*/
+    'recaptcha' => [
+        'api_url' => 'https://www.google.com/recaptcha/api/siteverify',
+        'site_key' => env('APP_RECAPTCHA_SITE_KEY'),
+        'secret_key' => env('APP_RECAPTCHA_SECRET_KEY'),
+    ],

];

ReCAPTCHA div标签安装将呈现

ReCAPTCHA是渲染所必需的,因此进行设置。
data-sitekey属性包含站点密钥,而data-callback属性包含提交时的回调函数。

资源/视图/表单/input.blade.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        FooBar Form
        <script src="https://www.google.com/recaptcha/api.js" async defer></script>
    </head>
    <body>
        // contents

        <form action="./entry/input" method="post" id="form">
+                <div class="g-recaptcha"
+                        data-sitekey="{{ config('app.recaptcha.site_key') }}"
+                        data-callback="onGrecaptchaSubmit"
+                        data-size="invisible"></div>
            // form inputs
        </form>
    </body>
</html>

调用reCAPTCHA

的API设置

全局定义回调函数。

另外,就我而言,我正在应用JS验证,
我希望不是在"按下提交按钮时"而是在"通过验证时"触发reCAPTCHA API,所以

使用

reCAPTCHA提供的grecaptcha.execute()功能随时执行reCAPTCHA。

资源/ js / form-efo.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
+ window.onGrecaptchaSubmit = function(request) {
+    $('form').submit();
+ };

$(() => {
    // 省略???

    if (validated()) {
      // 省略???
-     $('form').submit();
+     grecaptcha.execute();
    }
    // ???
});

这样就完成了正面的设置。

如果在本地环境中查看它,您将在右下角看到reCAPTCHA图标。

通常,如果有人输入并提交,它将按原样进行,但是
如果执行自动输入等,将会出现图像认证画面并被抓住。

后端侧reCAPTCHA身份验证实现

由于可能仅在客户端进行未经授权的突破,因此也请在后端检查身份验证。

简而言之,当reCAPTCHA API在客户端触发时,将发出令牌,
提交表单时,令牌是用键g-recaptcha-response发布的,因此请在后端检查该令牌。

中间件创建

有各种各样的方法,但是这次我们将使用中间件。
我正在使用curl,但是我认为可以使用Guzzle之类的库。

根据发布的密钥,在客户端发布的令牌和IP地址,检查是否有无效的提交。

如果您想了解有关

API的更多信息,请参考官方文档。
https://developers.google.com/recaptcha/docs/verify

应用程序/ Http /中间件/ CheckRecaptcha.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?php

namespace App\Http\Middleware;

use Closure;

class CheckRecaptcha
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if ($request->input('g-recaptcha-response')){
            $secret_key = config('app.recaptcha.secret_key');
            $url = config('app.recaptcha.api_url');
            $token = $request->input('g-recaptcha-response');

            $ch = curl_init();
            curl_setopt_array($ch, [
                CURLOPT_URL => $url,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_POST => true,
                CURLOPT_POSTFIELDS => http_build_query([
                    'secret' => $secret_key,
                    'response' => $token,
                    'remoteip' => $request->server->get('REMOTE_ADDR'),
                ]),
            ]);
            $_response = curl_exec($ch);
            curl_close($ch);

            $response = json_decode($_response);

            if (isset($response->success) && $response->success) {
                return $next($request);
            }
            else {
                return redirect('error'); // エラーページへリダイレクト
            }
        }
        return redirect('error'); // エラーページへリダイレクト
    }
}

从这里开始,仅涉及Laravel,因此,如果它是另一个框架,则可以跳过。

内核和

中注册中间件

应用程序/ Http / Kernel.php

1
2
3
4
5
6
7
8
9
10
11
    /**
     * The application's route middleware.
     *
     * These middleware may be assigned to groups or used individually.
     *
     * @var array
     */
    protected $routeMiddleware = [
        // 省略???
+       'recaptcha' => \App\Http\Middleware\CheckRecaptcha::class,
    ];

将中间件分配给应用程序表单的路由。

路线/ web.php

1
2
3
- Route::post('/entry/input', [\App\Http\Controllers\EntryInputController::class, 'input'])->name('entry.input');
+ Route::post('/entry/input', [\App\Http\Controllers\EntryInputController::class, 'input'])->name('entry.input')
+     ->middleware('recaptcha');

这样就完成了reCAPTCHA身份验证设置。

补充:设置输出日志

在后端执行API身份验证时,您可能希望输出响应的内容。

就我而言,我将日志输出设置如下。
如果发生身份验证错误,您可以看到状态代码和错误详细信息,这将使调试更加容易。

应用程序/ Http /中间件/ CheckRecaptcha.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if ($request->input('g-recaptcha-response')){
            $secret_key = config('app.recaptcha.secret_key');
            $url = config('app.recaptcha.api_url');
            $token = $request->input('g-recaptcha-response');

            $ch = curl_init();
            curl_setopt_array($ch, [
                CURLOPT_URL => $url,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_POST => true,
                CURLOPT_POSTFIELDS => http_build_query([
                    'secret' => $secret_key,
                    'response' => $token,
                    'remoteip' => $request->server->get('REMOTE_ADDR'),
                ]),
            ]);
            $_response = curl_exec($ch);
+           $_error = curl_error($ch);
            curl_close($ch);

            $response = json_decode($_response);
+           Log::info(
+               $_response ? [
+                   'recaptcha-result' => $response->success ? $response->success : $response['error-codes']
+               ] : ['recaptcha-error' => $_error]
+           );
+          
            return is_null($response) ? false : $response->success;
        }
        return false;
    }

使用Laravel!轻松实现Google reCAPTCHA!

这次,我将其设置为隐藏v2的安全级别1,但是Selenium机器人也可以播放它,没有用户无法申请的事情。

Bot对策可以通过相对简单的实现来采取,因此请尝试一下。

*参考页
https://developers.google.com/recaptcha/docs/invisible
没有日文版本,因此我这次进行了总结。