グーグルのスパム対策reCAPTCHAの導入と罠[PHP]
投稿フォームを用意してるwebサイトにとって、スパム対策としてはグーグルのreCAPTCHAが有効です
その導入方法と待ち受ける多数の罠の回避方法なんかを紹介します
なお、この記事はウェブサイトでの導入を対象にしています
ワードプレスに設置する場合はこちらの記事をご覧ください
ちなみにreCAPTCHAってのはこんなやつです
誰でも一回は見たことがあると思います

ちなみにこれはv2の古いバージョンで、パズルを選ぶやつなんかもあります
最新のv3はユーザの必要なアクションがなくなってるので、ユーザにかける負担が少なくなってます

導入方法
html
<form name="form">
<input type="hidden" name="g-recaptcha-response" id="g-recaptcha-response">
</form>
まずはレスポンスデータを入れるhiddenをhtmlフォーム内に入れておきます
javascript
<script src="https://www.google.com/recaptcha/api.js?render=reCAPTCHA_site_key"></script>
<script>
grecaptcha.ready(function() {
grecaptcha.execute('reCAPTCHA_site_key', {action: 'homepage'}).then(function(token) {
var recaptchaResponse = document.getElementById('g-recaptcha-response');
recaptchaResponse.value = token;
});
});
</script>
あらかじめ管理画面で取得したサイトキーを「reCAPTCHA_site_key
」にセットします(2箇所)
php
$secretKey = 'reCAPTCHA_secret_key';
$captchaResponse = filter_input(INPUT_POST, 'g-recaptcha-response');
$verifyResponse = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret={$secretKey}&response={$captchaResponse}");
$responseData = json_decode($verifyResponse);
if ($responseData->success) {
//人間だ!→処理を実行
}
else{
// ボットだ!、スパムボットが来たぞーー
}
レスポンスデータとシークレットキー「reCAPTCHA_secret_key」を付けてグーグルAPIを叩きます
そうするとAPIからレスポンスが返ってきます
人間の場合はsuccessがtrue、
ボットと判定された場合はfalseとなります
罠
タイムアウト
実はこれだけだと、人間なのにも関わらずボット判定される人が出てきてしまいます
原因はreCAPTCHAがタイムアウトするからです
入力フォームなんかに採用してると、ユーザによっては長い長文を書いたりしますよね?
その入力中にreCAPTCHA側がタイムアウトされてしまい失敗します
ちなみにデフォルトのタイムアウト時間は5、6分です
しかしそれなりの文章を書こうと思ったら5、6分なんて普通に経ってしまいます
このとき返ってくるエラーステータスは以下のものです
timeout-or-duplicate
対策としては色々あるんですが、とりあえず僕のサイトではこの「timeout-or-duplicate」を無視する処理を加えました
その対策を加えたPHPの全文コードは以下の通りです
$secretKey = 'reCAPTCHA_secret_key';
$captchaResponse = filter_input(INPUT_POST, 'g-recaptcha-response');
$verifyResponse = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret={$secretKey}&response={$captchaResponse}");
$responseData = json_decode($verifyResponse);
$timeout = false;
if(array_key_exists("error-codes",$responseData)){
$timeout = array_search('timeout-or-duplicate', $responseData->{'error-codes'});
}
if (!$responseData->success && $timeout === false) {
// ボットだ!、スパムボットが来たぞーー
}
else{
//人間だ!→処理を実行
}
APIからのレスポンスからerror-codesをチェックして、timeout-or-duplicateだった場合は人間として判定するというものです
対策としては他にも、一定時間ごとにreCAPTCHAをリセットするとか、送信する直前で発行するとかがありますが、一長一短ですね
最初は送信する直前でreCAPTCHAを発行するのが良いと思ってましたが、サブミットの直前に生成→送信をしてしまうとグーグル側が正しくスコアを算出できない可能性があるのでやめました
正しくスコアを算出できないと、そもそもスパム対策の意味がありませんから
タイムアウト時間は変更できない
この厄介なタイムアウト時間は変更できません
入力フォームに採用される機能なんだから、こんな短い時間でタイムアウトするとか普通に考えておかしいと思うんですが。。。
ちなみに僕以外にもそう考える人はいるみたいで、issuesにも登録されてますが今だに修正されて無いようです
error-codes
の取得方法
凄いつまんないことなんですが、引っかかったので。
jsonで取得したreCAPTCHAのレスポンスにエラーコードを格納している「error-codes」という項目があります
この取得方法について、ちょっと注意が必要です
連想配列はPHPでは普通、以下の形で取得できます
$responseData->success
しかし「error-codes」はハイフンを含んでるので、その形式ではエラーになります
こういう時は、以下のように{}で括る必要があります
// エラー!
$responseData->error-codes
// OK
$responseData->{'error-codes'}
ディスカッション
コメント一覧
まだ、コメントがありません
よくLoadingされてるDocs
新たにPostされたDocs
: ウェブサービス
メルカリやラクマの商品がいつ出品されたのかを調べる裏技
メルカリやラクマなどで商品を探してると、ときどき、 「この商品はいつ出品されたも ...: 仕事環境
15年前のエアコンに洗浄スプレーしたら想像以上にキレイになった
うちのエアコンは新品で購入してからすでに15年が経過しています にもかかわらず、 ...: Laravel
一定時間で消えるフラッシュメッセージを簡単に実装[Laravel8]
以前、手軽にフラッシュメッセージが実装できるnotieを紹介しました 今回は、そ ...: Laravel
ランダムな文字列やユニークなIDをLaravelで生成
random use Illuminate\Support\Str; // 引数 ...: スマホ
4,837円あげるって言うからOCNモバイルOneにLinksmateから乗り換えたんですよ
これまでは僕はスマホの通信会社に、MVNOのLinksmateを使ってきました ...HashMap
created_by
はやぴ
Web/アプリ開発エンジニア
Sierにてお堅いB向けのソフトウェア開発を経て、現在はC向けのWebやアプリを中心に開発しています。
Utilities