Laravel 生產實踐:為個人網站配置谷歌 reCAPTCHA 身份驗證系統

lyn510發表於2020-01-30

本教程主要針對為laravel 6 配置reCAPTCHA v2.0 checkbox的情況

第一部分: 什麼是reCAPTCHA?為何要配置它?如何選擇適合自己網站的身份驗證方式?

1.1 reCAPTCHA是什麼?
1.2 reCAPTCHA的優缺點
1.3 laravel驗證碼平行比較:mews/captcha?為何選擇reCAPTCHA?
1.4 reCAPTCHA的各個版本介紹,及如何選擇自己適用的reCAPTCHA:
1.5 為何選擇自行配置reCAPTCHA,而不是使用目前已有的、已經整合在laravel系統的包?

第二部分:為laravel6配置reCAPTCHA v2.0 checkbox 的手把手教程

2.1 安裝含有auth的全新laravel 6程式
2.2 配置reCAPTCHA
2.3 bonus:如何相容中文

之前緊急為站點配置了google reCAPTCHA驗證系統,避免盜號攻擊。將經驗總結寫作下列教程,回饋社群。
為了方便講解,本教程在空白laravel 6基礎上編寫,具有詳細的逐步過程。雖然我們的實際生產環節只在5.7框架版本使用,我們相信這個教程中提到的方法在5.7之後版本的laravel專案裡也會保持穩定。

1.1 reCAPTCHA是什麼?

reCAPTCHACAPTCHA 的衍生詞。CAPTCHA是 Completely Automated Public Turing test to tell Computers and Humans Apart 的縮寫,意為“全自動區分計算機和人類的圖靈測試”。reCAPTCHA是谷歌基於這個思路開發的一套具體的驗證規則。目前,它具有多個版本。

1.2 reCAPTCHA的優缺點

優點:

  • 獨立的軟體包,安裝和“拆卸”都便利
  • 聯網谷歌,根據往期記錄決定使用者的“真實性”,相對難以破解,更安全。
  • 免費

    缺點:

  • 聯網谷歌,你懂的,有那麼一點點……聯網問題。
  • 語言需要額外配置。
  • 其中一部分驗證的思維方式,可能不太符合中文語境的生活經驗與使用習慣。

1.3 laravel驗證碼平行比較:reCAPTCHA VS mews/captcha

提到reCAPTCHA,不得不先介紹laravel的另一個常用的驗證碼系統 mews/captcha

mews/captcha 是集合在laravel系統上的一個方便好用美觀的圖片驗證碼系統。它隨機生成一個含有邀請碼字元的圖片,要求使用者進行識別,輸入圖上的字元,完成驗證。官方程式碼地址:https://github.com/mewebstudio/captcha

這個系統文件完備,非常方便配置,而且對於流量不高的普通個人工程來說,具有不錯的防護效果。mews/captcha 本身的安裝文件就很完整,可以直接照著安裝。如果你想要中文的安裝介紹,可以參考這個網址:分享:【擴充套件推薦】mews/captcha 圖片驗證碼解決方案

之前研究過很多目前已有的、免費可用的、相容laravel的驗證碼系統。坦誠地說,如果你是剛開始進行建站的開發者,使用laravel,又需要配置驗證碼,mews/captcha 是你的首選。儘量主要精力花在你的核心服務邏輯上。

但是……我們實際使用 mews/captcha 的悲慘結果是,它比較容易被破解。基於本站實際體驗,後臺資料跟蹤發現,在使用它的第一個月,預設版式的驗證碼被破解。更換到inverse圖片之後的大概第二個月,“inverse”版式也被破解了。

因此,緊急更換並配置reCAPTCHA,成了我們被迫的、無奈的結果。


1.4 reCAPTCHA的各個版本介紹,及如何選擇自己適用的reCAPTCHA:

reCAPTCHA v1.0:已廢棄
reCAPTCHA v2.0: 目前主流使用的reCAPTCHA系統,具有下面幾個“變種”:
  • “im not a bot checkbox” 透過點選方框,決定使用者是否真人。如果使用者的“可疑性”比較高,進一步要求使用者做圖片識別(比如找公交車、找人行橫道……)直到使用者作出正確的判斷再放行。
  • “invisible”recaptcha 隱藏在幕後,直接透過使用者的行為判斷是否真人的recaptcha,是reCAPTCHA 3.0 的前置產品。個人理解,目前的v3.0基本完全覆蓋了這部分的功能,因此沒有采用的必要。
  • 專門適用android的recaptcha
reCAPTCHA v3.0:最新推出的reCAPTCHA

只對網站提供使用者的安全分值(0-1,1代表真人,0代表bot),由網站自行判斷下一步要做什麼。

結論1: 對於個人非安卓的開發者,只需要從reCAPTCHA v2.0 checkbox和reCAPTCHA v3.0中挑一個就可以了。

以下繼續分點闡述這兩個版本recaptcha的好壞比較,方便使用者選擇最適合自己的驗證方式:

reCAPTCHA v2.0 checkbox

主要好處:
  • 有預置的fallback。如果使用者的分數較為可疑,並不會拒絕使用者,而是要求使用者用進一步的圖片識別繼續驗證自己身份,驗證之後就允許訪問。
    主要壞處:
  • 圖片識別過程非常繁瑣,可能會有較多的使用者抱怨(類似:“為什麼我每次登陸都要點六十次立交橋”。當然後來我們發現這跟使用者的瀏覽器用了什麼也有關係)

reCAPTCHA v3.0

主要好處:
  • 可以用在你網站的所有頁面(無論是否含有表單),並根據不同的頁面配置不同的處理決定
  • 可以根據實際情況,自定義對分數的後續處理(比如說,在某些網站,0.5是可疑使用者不能允許訪問,而在另一些網站,沒必要阻止0.5的使用者訪問)
主要壞處:
  • 如果你因為分數很低直接拒絕了某些使用者,你可能會永久地失去他們。因此,recaptcha3.0需要自行配置合理的fallback辦法,這對個人開發者來講是一個比較大的業務負擔。

結論2: 目前reCAPTCHA 3.0並不能直接取代reCAPTCHA 2.0 checkbox(這可能也是為什麼谷歌並沒有停止2.0業務的原因)。開發者應根據自己的情況自主選擇,而不是片面升級到最新版本的reCAPTCHA

結合專案當前的主要需求:在註冊、登陸等重要頁面進行身份驗證,避免bot攻擊,但也不要把真人踢走的需求,我們選擇reCAPTCHA v2.0 checkbox作為新的驗證手段。

主要是因為,大部分laravel和reCAPTCHA系統的整合包,並不支援reCAPTCHA的global配置(也就是說會被牆),需要自己進行微小的調整。其次,因為命名的問題,他人的reCAPTCHA整合包,可能會和其他的驗證碼方式衝突,如果開發者打算在系統里加入多個驗證方式,需要特別注意這一點。
實際上,個人自行配置reCAPTCHA非常簡單,也很靈活,命名衝突也非常好解決。

接下來的教程裡,將新建一個全新空白laravel工程,併為它配置reCAPTCHA v2.0 checkbox系統
全部程式碼見:https://github.com/lyn510/reCAPTCHA
我們這就開始吧!

2.1 安裝含有auth的全新laravel6程式

首先安裝一個版本為 laravel 6 的全新程式。 這和laravel5的配置過程會略有不同。

$ composer create-project laravel/laravel reCAPTCHA

接下來安裝預設的auth身份驗證方式(就是基礎的登陸註冊系統)

$ composer require laravel/ui --dev

上面的指令安裝了預設ui

$ php artisan ui vue --auth

上面的指令安裝了登陸介面

$ npm install && npm run dev

上面指令會compile對應的css檔案,讓ui介面的內容得以被呈現出來。它會需要比較長的時間來執行,視網路環境而定,請耐心等待。

接下來,為了正常使用登陸系統,需要建立對應的資料庫。本教程裡使用的是mysql。

建立一個mysql資料庫,資料庫的名字叫reCAPTCHA-auth, 使用者名稱root, 密碼留空。

配置.env檔案,使程式能連線到資料庫:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=reCAPTCHA-auth
DB_USERNAME=root
DB_PASSWORD=

之後,回到terminal,執行migrate命令

$ php artisan migrate

接著檢視一下目前的情況

$ php artisan serve

從瀏覽器開啟對應的連結http://127.0.0.1:8000,就可以正常的登陸系統。(在terminal中,執行 control+C,就可以退出)。

2.2 配置reCAPTCHA

下面,我們將reCAPTCHA安排進來。

2.2.1 首先使用composer,安裝官方包:

$ composer require google/recaptcha

接著一步步完成後端的配置。

2.2.2 建立一個extended validator來進行對應的測試。

新建檔案:app\Validators\reCaptchaCheckbox.php

<?php
namespace App\Validators;

use ReCaptcha\ReCaptcha;

class reCaptchaCheckbox{

    public function validate($attribute, $value){
        $captcha = new ReCaptcha(env('RECAPTCHA_CHECKBOX_SECRET'));
        $response = $captcha->verify($value, $_SERVER['REMOTE_ADDR']);
        return $response->isSuccess();
    }

    public function message($message, $attribute, $rule, $parameters){
        return ;
    }

}

下面將validator註冊進入預設的validation系統
修改app\Providers\AppServiceProvider.php

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Validator;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        // 增加這行程式碼,擴充套件預設 Validator
        Validator::extend('recaptcha', 'App\Validators\reCaptchaCheckbox@validate');
    }
}

上面這裡要增加兩行程式碼,一行排程validator,另一行擴充套件validator的boot方式。

2.2.3 接著我們要求,在使用者登入(login)的時候,需要首先進行人機驗證。

修改檔案app\Http\Controllers\Auth\LoginController.php

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;

class LoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */

    use AuthenticatesUsers;

    /**
     * Where to redirect users after login.
     *
     * @var string
     */
    protected $redirectTo = RouteServiceProvider::HOME;

    // 這裡,重寫login方式,使得recaptcha的驗證成為這部分必須的驗證環節
    public function login(Request $request)
    {
       $request->validate([
            'g-recaptcha-response' => 'required|recaptcha'
        ]);
        $this->validateLogin($request);

        if ($this->hasTooManyLoginAttempts($request)) {
            $this->fireLockoutEvent($request);
            return $this->sendLockoutResponse($request);
        }

        if ($this->attemptLogin($request)) {
            return $this->sendLoginResponse($request);
        }

        $this->incrementLoginAttempts($request);

        return $this->sendFailedLoginResponse($request);
    }

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }
}

2.2.4 再下面,我們要求前端展示這個人機驗證的檢視

修改檔案resources\views\auth\login.blade.php

...
<div class="g-recaptcha" data-sitekey="{{ env('RECAPTCHA_CHECKBOX_SITEKEY') }}"></div>
<button type="submit" class="btn btn-primary">
                                    {{ __('Login') }}
</button>

修改檔案resources\views\layouts.app.blade.php

...
<!-- Scripts -->
    <script src="{{ asset('js/app.js') }}" defer></script>
    <script src="https://www.recaptcha.net/recaptcha/api.js"></script>
...

注意上面這裡,使用www.recaptcha.net,而非www.google.com,來避免在大陸的訪問被牆。

2.2.5 最後別忘了配置開發者專用的key

首先登陸Recaptcha註冊官網:https://www.google.com/recaptcha/admin#lis...
選擇v2 checkbox,輸入對自己網站的配置即可
reCAPTCHA申請
此處domain選填了127.0.0.1,因為有本地測試情況。使用valet的朋友,在這裡新增valet的域名縮寫(比如xxxxxx.test),親測也是可以有效完成本地測試的。

確認後,就會獲得相關key
從google申請獲取的開發者使用reCAPTCHA的相關key

配置到.env裡:

RECAPTCHA_CHECKBOX_SECRET=6Lc6u8oUAAAAAPI4a0lYImLIWyR50xxxxxxxx
RECAPTCHA_CHECKBOX_SITEKEY=6Lc6u8oUAAAAALvO2Tfjh5zRheJGuyxxxxxxx

所有程式端的配置就完成了
別忘了重新配置目錄

$ composer dump-autoload

重新開啟頁面

$ php artisan serve

註冊頁面包含reCAPTCHA人機驗證辦法

此時,只要透過人機測試,就可以正確登陸。

2.3 bonus:如何相容中文

2.3.1 如何配置中文reCAPTCHA介面?

2.3.1.1 方法1: 可以直接要求js配置為中文

修改檔案resources\views\layouts.app.blade.php

...
<!-- Scripts -->
    <script src="{{ asset('js/app.js') }}" defer></script>
    <script src="https://www.recaptcha.net/recaptcha/api.js?hl=zh-CN"></script>
...

註冊頁面-人機驗證-中文

2.3.1.2 方法2: 也可以設定要求js響應系統環境語言。

修改檔案:resources\views\layouts.app.blade.php

...
<!-- Scripts -->
    <script src="{{ asset('js/app.js') }}" defer></script>
    <script src="https://www.recaptcha.net/recaptcha/api.js?hl={{ app()->getLocale() }}"></script>
...

注意這裡app()->getLocale()需要自己按照官方doc繼續配置多語言,就不再詳細寫了。

2.3.2 如何配置中文reCAPTCHA介面的錯誤反饋?

很簡單,修改檔案resources/lang/zh-CN/validation.php

...
'custom'               => [
        'g-recaptcha-response' => [
            'required' => '請先透過人機身份驗證,再提交資訊。如果相關測試不能正確顯示,請檢查瀏覽器設定。',
        ]
    ],
...

之前有一些排版的問題,重新編輯了頁面

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章