Contact Form 7でスパムが来たので、reCAPTCHA v2 をつけてみた

サイトを立ち上げて、お問い合わせフォームをつけたら、スパムが来るようになってしまいました。それで対応を検討ました。

Contact Form 7でスパムが来たので、reCAPTCHA v2 をつけてみた

まず、対応として「reCAPTCHA v2」を導入しました。一つ目の対応です。

reCAPTCHA v2の導入

サイトを利用していて、「私はロボットではありません」というチェックボタンを見かけませんか?それを実装して、スパム対応としてみますね。

Google reCAPTCHAに「新しいサイトを登録する」

Google reCAPTCHA:初期表示

この画面で、ラベル(何でも可)、タイプ、ドメイン、を設定します。

タイプ

「reCAPTCHA v2」と「reCAPTCHA v3」をを選択します。今回は『reCAPTCHA v2』にします。

『reCAPTCHA v2』を選択して、「私はロボットではありません」チェックボックスを選択してみます。

ドメイン

ドメインには reCAPTCHA を使用するサイトを入力してます。

『reCAPTCAH 利用条件に同意する』をチェックして、『送信』ボタンを押します。

送信ボタンを押すと、サイトで使用するキーを取得できます。

上部の『サイトキー』をコピーしてきます。

コンタクトフォームに実装

次に取得したキーを使用して、実際のお問い合わせフォーム内に埋め込むことにします。

固定ページからお問い合わせページの編集画面を表示させます。

右クリックから「カスタムHTML」の要素にします。

HTML/Javascriptのコードを書き込みます。

<!-- reCAPTCHAエリア -->
<div id="reCAPTCHAArea" style="margin-top:5px"></div>

<script type="text/javascript">
// オンロードで「reCAPTCHA」生成
function onloadCallback(){
       grecaptcha.render('reCAPTCHAArea', {
              'sitekey' : '(事前に生成しコピーしたサイトキー)',
              'callback' : checkboxClicked, 
              'expired-callback': sessionExpired,
       });
}

// 「私はロボットではありません」クリック後の処理
function checkboxClicked(){
var oFormObjects = document.getElementsByTagName('form');
if ( oFormObjects.length > 0 ) {
       for ( var i=0; i < oFormObjects.length;i++ ) {
              var oMainForm = oFormObjects[i];
              if ( oMainForm.className.indexOf('wpcf7-form ') >= 0 
                  && oMainForm.method == 'post' ) {
                     var pArea = document.createElement('p');
                     pArea.id = 'pBtnArea';
                     var oBtnSend = document.createElement('input');
                     oBtnSend.type ='submit';
                     oBtnSend.value = '送信';
                     oBtnSend.className = 'wpcf7-form-control wpcf7-submit';
                     pArea.appendChild(oBtnSend);
                     oMainForm.appendChild(pArea);
              }
       }
}
}
// タイムアウト時
function sessionExpired() {
       var pBtnArea = document.getElementById('pBtnArea');
       pBtnArea.parentNode.removeChild(pBtnArea);
}
</script>
<!-- ライブラリ読み込み -->
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&amp;render=explicit" async="" defer=""></script>

サンプルコードの説明

まず、「私はロボットではありません」チェックの領域を設定します。

<!-- reCAPTCHAエリア -->
<div id="reCAPTCHAArea" style="margin-top:5px"></div>

次にreCAPTCHAのAPIをロードします(サンプルでは最終行に記載してあります)。

<!-- ライブラリ読み込み -->
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&amp;render=explicit" async="" defer=""></script>
パラメータ意味
onloadapi.js 読み込み後実行するロールバック関数【任意】
renderウィジェットを明示的にレンダリングする場合は、「explicit」、デフォルトでは「onload」で、最初の『g-recaptcha』タグ内のウィジェットをレンダリングします。【任意】
hljaやen などの言語コードを指定。ウィジェットをレンダリングする際の言語を指定する。【任意】

全部任意のパラメータなので、別に指定しなくても動作しますね。

<script type="text/javascript">
// オンロードで「reCAPTCHA」生成
function onloadCallback(){
       grecaptcha.render('reCAPTCHAArea', {
              'sitekey' : '(事前に生成しコピーしたサイトキー)',
              'callback' : checkboxClicked, 
              'expired-callback': sessionExpired,
       });
}

onloadでjavascript関数を呼び出し「reCAPTCHA」を生成します。grecaptcha.render関数を呼び出します。

最初のパラメータ「container」には、reCAPTCHAを生成したいDIVのIDを指定します。

2つ目のパラメータは、配列のパラメタを指定することになります。

grecaptcha.renderのparameter

サンプルで指定した3つのパラメータのみ説明します。

オプション説明
sitekey事前に取得した『サイトキー』をここに指定します。
callback「私はロボットではありません」チェックボックスがONになると実行されるjavascript関数を指定します。
expired-callback「私はロボットではありません」チェックボックスがONになった後、reCAPTCHAレスポンスの有効期限が切れた場合、呼び出されるjavascript関数を指定します。

次に、「私はロボットではありません」がチェックされると呼び出される関数を次のようにしました。

// 「私はロボットではありません」クリック後の処理
function checkboxClicked(){
var oFormObjects = document.getElementsByTagName('form');
if ( oFormObjects.length > 0 ) {
       for ( var i=0; i < oFormObjects.length;i++ ) {
              var oMainForm = oFormObjects[i];
              if ( oMainForm.className.indexOf('wpcf7-form ') >= 0 
                  && oMainForm.method == 'post' ) {
                     var pArea = document.createElement('p');
                     pArea.id = 'pBtnArea';
                     var oBtnSend = document.createElement('input');
                     oBtnSend.type ='submit';
                     oBtnSend.value = '送信';
                     oBtnSend.className = 'wpcf7-form-control wpcf7-submit';
                     pArea.appendChild(oBtnSend);
                     oMainForm.appendChild(pArea);
              }
       }
}

チェックボックスをONにすると、このサンプルではinputエレメントを生成し、名称「送信」のsubmitボタンを生成するようにしました。

つまり、この画面の初期表示時にはメールの送信ボタンはなく、チェックボックスがチェックされると、「送信」ボタンが表示されることになります。

「私はロボットではありません」をチェックしたものの、reCAPTCHAの有効期限が切れたとき

// タイムアウト時
function sessionExpired() {
       var pBtnArea = document.getElementById('pBtnArea');
       pBtnArea.parentNode.removeChild(pBtnArea);
}
</script>

「私はロボットではありません」をチェックしたものの、reCAPTCHAの有効期限が切れたとき、このサンプルでは、「送信」のINPUTオブジェクトを削除(removeChild)しています。

もう一度、「私はロボットではありません」をチェックしないと、メールを送信できないような仕様にしてあります。

reCAPTCHA v2を導入した結果/その顛末

この対策導入前からスパムが来ていて、この対応をすれば、スパムが止まるかなぁ?って思ったのですが、止まりませんでした。

原因は、やっぱりこの「reCAPTCHA v2」の「私はロボットではありません」の対応では、クライアント側のチェックなので、一度、スパムにメールを送れる手口がスパム送信側にわかってしまうと、たとえ入口を塞いだつもりでも、スパム側がメールを送れるルートがわかっているので、効果がありませんでした。

Contact Form 7の「クイズ」を使ってスパム対策

reCAPTCHA v2だけでは、既に送られているスパムは止められなかったので、今度は「reCAPTCHA v2」で「クイズ」を設置することにしました。

「クイズ」設置

「クイズと回答」項目に問題文とパイプ(|)で区切って解答を設定します。

その後、「タグを挿入」ボタンを押すと、クイズがテンプレートに挿入されます。

その後、このテンプレートを保存し、画面を確認すると、以下のようになり、クイズが設定されています。

画面を見るとクイズが設定されています。これに正解しないと、メールが送れなくなりました、スパムメールも簡単には飛ばせなくなります。

実際、わたしにもスパムメールが飛んでこなくなりました。

まとめると、既に飛んできているスパムに対しては「reCAPTCHA v2」では意味がありませんでした。実際には、Contact Form 7の「クイズ」が有効だと思います。これらは、サーバ側でチェックを行ってくれるからです。

これらの対応について、「reCAPTCHA v2」やContact Form 7のスパム対策のご参考となればと思います。