網路上總會有人為了一己私利,透過機器人(robot)來快速填寫並送出網頁上的表單,導致該網站的帳號密碼被破解,或者販賣的商品立刻被有心人士一掃而空(倒買倒賣),又或是資料庫的資料在短時間內被全部爬出來。為了防範機器人來我們的網站上搗亂,最好將Google提供的reCAPTCHA真人驗證機制加入網站中。
CAPTCHA給人的感覺就是要讓使用者去完成艱難的圖形任務,或是回答一些古怪的問題,來證明使用者自己是真人。然而Google第三代的reCAPTCHA已經完全不需再讓使用者傷腦、傷眼睛了!第三代的reCAPTCHA甚至不需要使用者用滑鼠進行任何「勾選」或是「滑動」的動作,就可以判斷使用者是否為真人。
reCAPTCHA v3會利用範圍0.0~1.0的分數值來表示使用者可能比較像機器人還是可能比較像真人,數值愈高愈像真人。Google官方雖然建議將0.5以上的值當作真人,但實測時真人似乎都是0.9以上,所以為了擋掉更多像人的機器人,我們其實可以選用比0.5更高的數值作為門檻。
除了單純以分數值來區分機器人與真人之外,我們也可以實作額外的商業邏輯來更進一步地驗證使用者的身份。例如,使用者雖然用正確的帳號和密碼成功登入帳號,但是他的reCAPTCHA v3分數值只有0.4或是0.5時,我們可以要求他去信箱收驗證信才能繼續登入。
此外,reCAPTCHA v3還提供了action欄位,可以方便我們分析訪客們的行為。
reCAPTCHA v3 for Rocket Framework
「reCAPTCHA v3 for Rocket Framework」是筆者開發的套件,可以幫助開發者將reCAPTCHA v3加進Rocket應用程式中。
Crates.io
Cargo.toml
使用方法
註冊網站並取得reCAPTCHA v3的兩個金鑰
首先來到這個頁面來註冊要使用reCAPTCHA v3的網站。
然後會得到兩個金鑰,請記錄下來。
將reCAPTCHA v3的兩個金鑰加進Rocket的設定檔中
接著將剛才得到的reCAPTCHA v3的兩個金鑰,加進Rocket的設定檔Rocket.toml中的recaptcha欄位下的v3欄位。這個v3欄位下有一個必填欄位secret_key,即用來「建立網站和 reCAPTCHA 之間的通訊」的金鑰。還有一個選填欄位html_key,即「向使用者顯示的 HTML 程式碼中」使用的金鑰。
舉例來說:
[default.recaptcha.v3]
html_key = "6Lf6dLIUAAAAAAxghN7nH6m_yuLfHwdD3N7FpanR"
secret_key = "6Lf6dLIUAAAAAHdJ4e0nsv-8OpFH-7Oad1XQ95rq"
這個html_key欄位主要是給開發者自己用的,可以利用HTML模板引擎將html_key欄位的值填入HTML中。
將reCAPTCHA v3加入HTML中
預設的reCAPTCHA v3徽章(badge)會被浮動放置在網頁的右下角,挺難看的。所以此處簡單介紹用內聯(inline)的方式來加入reCAPTCHA v3的徽章。
首先在適當的位置上加入:
<script src="https://www.recaptcha.net/recaptcha/api.js?render=explicit&&onload=onReCaptchaLoadCallback" defer></script>
<script>
function onReCaptchaLoadCallback() {
var clientId = grecaptcha.render('inline-badge', {
'sitekey': 'recaptcha_key',
'badge': 'inline',
'size': 'invisible'
});
grecaptcha.execute(clientId, {action: 'action_name'}).then(function (token) {
// save the token
});
}
</script>
注意這邊引用JavaScript程式時使用的網域為www.recaptcha.net而不是www.google.com,這是為了讓中國地區也可以使用reCAPTCHA v3。而在其後的JavaScript程式碼中,recaptcha_key的地方要填入html_key欄位的值。action_name的值則設訂一個自己看得懂的名稱就好了,方便用來分析數據。inline-badge則是要用來顯示reCAPTCHA v3徽章的元素ID。
當reCAPTCHA v3執行成功後,會回傳一個記號(token),要把這個token的值記下來,之後還要跟著表單內容一同傳給我們的Web應用程式來驗證。
將reCAPTCHA v3加入Rocket中
rocket_recaptcha_v3這個crate中的ReCaptcha結構體,提供了fairing關聯函數,可以回傳一個整流片。這個整流片會在Rocket的Attach階段,讀取Rocket.toml設定檔中剛才介紹的secret_key和html_key欄位,來建立ReCaptcha結構體的實體,並註冊給Rocket作為應用程式狀態。
use rocket_recaptcha_v3::ReCaptcha;
...
rocket::build().attach(ReCaptcha::fairing())
驗證reCAPTCHA v3的記號
rocket_recaptcha_v3這個crate中的ReCaptchaToken結構體,可以作為參數守衛、查詢守衛或是實作了data::FromData特性的結構體的欄位。我們可以呼叫ReCaptcha結構實體的verify方法,透過參數傳入ReCaptchaToken結構實體的參考,和一個選用的ClientRealAddr結構實體參考,來驗證使用者的真人程度。
例如:
#[macro_use]
extern crate rocket;
use rocket::{form::Form, response::Redirect, State};
use rocket_recaptcha_v3::{ReCaptcha, ReCaptchaToken};
#[derive(Debug, FromForm)]
struct LoginModel {
username: String,
password: String,
recaptcha_token: ReCaptchaToken,
}
#[post("/login", data = "<model>")]
async fn login_post(
recaptcha: &State<ReCaptcha>,
model: Form<LoginModel>,
) -> Result<Redirect, Redirect> {
match recaptcha.verify(&model.recaptcha_token, None).await {
Ok(verification) => {
...
},
Err(err) => {
...
},
}
}
驗證真人
若reCAPTCHA v3的記號驗證成功,ReCaptcha結構實體的verify方法會回傳一個ReCaptchaVerification結構實體,其score欄位即為分數值。用if結構來判斷分數值的高低來決定後續要做的動作。
例如:
#[post("/login", data = "<model>")]
async fn login_post(
recaptcha: &State<ReCaptcha>,
model: Form<LoginModel>,
) -> Result<Redirect, Redirect> {
match recaptcha.verify(&model.recaptcha_token, None).await {
Ok(verification) => {
if verification.score > 0.7 {
...
} else {
...
}
},
Err(err) => {
todo!();
},
}
}
完整的範例可以查看「reCAPTCHA v3 for Rocket Framework」專案中的examples目錄。




