グーグルのスパム対策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'}
ディスカッション
コメント一覧
まだ、コメントがありません
新たにPostされたDocs
: ツール関連
キーボードを銀軸から赤軸に買い替えた話
約3年半前、仕事で使うキーボードとしてARCHISS ProgresTouchの ...: スマホ
楽天モバイルがおすすめできない人の特徴とは?
楽天モバイルの最強プランをおすすめできない人の特徴を簡単にまとめてみました また ...: システム開発
なぜスクラムがつらいのか?開発現場が疲弊するのか?スクラムに対する違和感と共に原因を考えてみた
今ではどこの開発現場に行っても、やれスクラムスクラムと、まるでスクラムでもやって ...: Laravel
1つのテーブルを複数のテーブルと結合したい【Laravel10】
1つのテーブルを2つの異なるテーブルに対して結合したいケースがあったのでLara ...: Laravel
Laravelで複数画像アップロード時のvalidateを指定【Laravel10】
jQuery - Image Uploaderを使って、フォームから複数の画像を ...HashMap
created_by
はやぴ
Web/アプリ開発エンジニア
Sierにてお堅いB向けのソフトウェア開発を経て、現在はC向けのWebやアプリを中心に開発しています。
Utilities