PHP
JavaScript
reCAPTCHA

reCAPTCHA V3導入の問題点

結構ハマるなこれ。

ヾ(・ω<)ノ" 三三三● ⅱⅲ コロコロ♪


------------------- ↓ 余談はここから ↓-------------------

スパム対策にGoogle謹製のreCAPTCHAを導入することは多いと思う。

I'm not a robot でパズルやらされる例のアレだが、

Version3.0ではあのパズルがなくなって、

AIで判別するようになるらしい。

実装はV2とほぼ一緒で簡単に終わったなと思った。

ところが、数日後、

投稿者数が減ったような気がする

という連絡が。

(゚-゚) こりゃあかんやつやも。

こちらとしてはGoogleの実装例そのまま載せたのだが、

エラーを解析した結果、

timeout-or-duplicate というエラーばかりだった。

マニュアルには

timeout-or-duplicate

The response is no longer valid: either is too old or has been used previously.

https://developers.google.com/recaptcha/docs/verify

と記載されているが、

このtoo oldとは何時間のことなのか。

実際に測ってみたら。5分だった。

_人人人人人人人人_

> Too Old: 5分 <

 ̄Y^Y^Y^Y^Y^Y^Y^Y^ ̄

有効期限を延ばす手段は管理画面とかにもない。

Googleさん、そりゃねーよ。

さて、困った。これで実装方法を大幅に変えなきゃならん。

方法は3つ。


  1. タイマーでtokenを再発行

  2. サブミットの直前で発行

  3. timeout-or-duplicateを許容する

(。_。) さて。。。


------------------- ↓ 本題はここから ↓-------------------


タイマーでtokenを再発行

コードはこんな感じになるだろうか

grecaptcha.ready(function() {

grecaptcha.execute('reCAPTCHA_site_key', {action: 'user/register'});
var ticker = setInterval(function(){
try{
grecaptcha.reset();
clearInterval(ticker);
} catch(e) {}
},250);
}

一定時間が経過した時点でresetを実行する。

これでキーが再発行される(らしい)

setIntervalかsetTimeoutかはお好みで。


サブミットの直前で発行

コードはこんな感じになるだろうか

(Jquery記述で申し訳ない)

  grecaptcha.ready(function() {

$('.recaptcha')
.on('click', function () {
grecaptcha
.execute('reCAPTCHA_site_key', {action:'article/edit'})
.then(function(token) {
$('form:first').submit();
});
});
});

サブミットボタン(type=button)を押したときに、

Googleからキーを発行して貰い、

それが完了したらsubmitを実行する流れ。

これであればタイムアウトが5分でも問題は起こらない。


timeout-or-duplicateを許容する

Googleサーバーにverify掛け、

bot判定(Success:false)されたときに結果JSONは以下のような感じになる。

{

"success": false,
"error-codes": [
"timeout-or-duplicate"
]
}

このerror-codesを判別してtimeout-or-duplicateの時はそのまま受け付ける。


------------------- ↓ 後書はここから ↓-------------------

実際採用したのは3番目。

timeout-or-duplicateを許容するである。

タイマーはなるべく避けたかったし、

JSゴリゴリでテスト満載も避けたかったのがその理由。

参考記事:

https://stackoverflow.com/questions/48133487/getting-invisible-recaptcha-to-trigger-on-page-load