[wp]CF7でreCAPTCHAを使わずにスパム対策する方法メモ

そんなときもある。

スパムメールについて

とりあえず、AkimetだとコメントだけでなくContactForm7もカバーしてくれるらしい。だけど無料で使える条件が厳しいというか、商用利用の時点でアウトらしい。予算があるならいいんでしょうが、無条件に選択するのは難しい。金で片付けずにケチりたい人は多い。

で、無料でやりたいならantispam beeが優秀らしい。だけどこれは対象がコメントだけなので問い合わせフォームをカバーできない。

問い合わせフォームを無料で対策したいならGoogleのreCAPTCHAを入れたらいい。まあ分かる。v3になってからはユーザー操作の手間が増えなくなったんで助かる。だけども、WEBサイト全体で発火するもんだから読み込みやら処理が無駄に増えてしんどいことになる。一応functions.phpで限定できるけども。

まあ、プラグインもそうだけどあんまり外部のサービスを使いたくないって考えは地味に昔から根強く存在する。今回はそっち方面での、自前で何とか頑張ろうねって話。

問い合わせ内容にひらがなが入ってなかったら弾く

一部で流行ってるみたいで、同じコードがあっちこっちに書かれてる。

Contact Form 7 海外からのスパム対策!お問い合わせ本文が全て外国語の場合は送信できないようにする
WordPress ブログを運営していると必ずといってよいほど発生する「お問い合わせからの英語等のスパムメール」。今回は「Contact Form7 を用いたお問い合わせフォームから送信される外国語メールだけをピンポイントでシャットアウトする方法」を紹介します。

カタカナだったらこうなりますね。

//メールフォームの textarea にカタカナがないと送信失敗(contact form7)
add_filter('wpcf7_validate_textarea', 'wpcf7_validation_textarea_katakana', 10, 2);
add_filter('wpcf7_validate_textarea*', 'wpcf7_validation_textarea_katakana', 10, 2);

function wpcf7_validation_textarea_katakana($result, $tag)
{
$name = $tag['name'];
$value = (isset($_POST[$name])) ? (string) $_POST[$name] : '';

if ($value !== '' && !preg_match('/[ァ-ン]/u', $value)) {
$result['valid'] = false;
$result['reason'] = array($name => 'エラー / この内容は送信できません。');
}

return $result;
}

実用性のあるバリデーションを考える

お仕事用に作成するメールフォームだと、input各種で必要情報を入力して、textareaはその他お問い合わせ内容的な感じで任意項目になってることは珍しくない。

上記のやつは空欄またはひらがなを含まない場合に蹴ってるんで、ちょっと合わない。

なので、仕様を弄る。

構想

ContactForm7でもって日本人対象の問い合わせフォームを設置するとして。

textareaの記入は任意だからバリデーション対象として当てにできない。スパムだったら書いてくるだろうけど、当てにすべきじゃない。ということで他の項目から選ぶ必要がある。

パッと思いつくのは名前のフリガナ。そもそも実務的にも地味にないと困るやつだし、あって損はない。通常使う際は自動挿入のjsを仕込んでおいて、だから日本人にとって問題のない構成。で、スパムだったらjsを無視して文字列を突っ込んでくる。

つまり、カタカナの入力もしくはその他の2択に絞れるのでやっていけますね、という感じ。

なお、名前の場合は漢字・ひらがな・カタカナを網羅しなきゃいけないのでダメです。

コード

対象はtextareaじゃないのでadd_filterも修正する必要がある。

add_filter('wpcf7_validate_text', 'wpcf7_validation_text_katakana', 10, 2);
add_filter('wpcf7_validate_text*', 'wpcf7_validation_text_katakana', 10, 2);
function wpcf7_validation_text_katakana($result, $tag){
    $name = $tag['name'];
    if(false !== strpos($name, 'furi') ||false !== strpos($name, 'kana')) {
        $value = (isset($_POST[$name])) ? (string) $_POST[$name] : '';
        if ($value !== '' && !preg_match('/[ァ-ン]/u', $value)) {
            $result['valid'] = false;
            $result['reason'] = array($name => 'エラー / この内容は送信できません。');
        }
    }
    return $result;
}

ここで注意点が5行目のこれ。

    if(false !== strpos($name, 'furi') ||false !== strpos($name, 'kana')) {

フリガナ用のinputを指定しなきゃいけないんで、条件分岐で拾えるようにnameに規則性をもたせる必要がある。この場合では、nameの中に「furi」もしくは「kana」が入ってたらバリデーションが発火するということになる。環境に合わせてこっちを変えるなり、フォーム側を変えるなりする。

という内容。

フリガナをひらがなにしたければ指定文字を変える。

        if ($value !== '' && !preg_match('/[ぁ-ん]/u', $value)) {

元のコードと比べたら調整が必要で面倒くさい作りになっちゃうんだけど、仕方ないですね。逆に言えばこうすることで特定の項目に仕込めるようになる。悪いことばかりじゃない。

問題点

簡単な話で、スパムがカタカナを使ってきたら詰みます。

まとめ

処理のこともあるんだけど、CORSとかのセキュリティを気にすると外部サービスの使用がかなりしんどくなるんですよ。だから内政でうまいことやっていける手段は持っておかないといけない。他責にできないから自己責任の範疇で頑張るしかないだけどね。

余談

CF7に「承認確認」があるけど、言ってみればただのチェックボックスだからスパムは普通にチェック入れてくるでしょうよって感じがして、スパム対策として入れるのは微妙だと思う。減りはしても消えはしないみたいな記事もあったし、対人として仕込むかどうかを考える程度にするのがいいんじゃないですかね。

動作チェックについて

スパムが来る環境に仕込むのが最適。

とはいえいきなり切り替えるのはよろしくないので、reCAPTCHAと共存させてみるなど。

送られたスパムはreCAPTCHAが弾く、そもそも送られる前にエラーにするのが今回の内容。

だから、効果が出たらreCAPTCHAの管理画面でリクエスト数がなくなる(減る)ことになる、はず。

追記:動作チェックできたので

コードを追加してreCAPTCHAと共存させた。しばらくおいてみたんだけど、reCAPTCHA側では相変わらずリクエスト数をカウントしまくってる。

意味なかったかなと思いつつ、ひょっとしてと思ってreCAPTCHAを切った。

そしたらスパムメールは届いてないという。

つまり、reCAPTCHAは送信されてるかどうかは無視して、とにかくリクエストを拾ってるくさい。

そういうやつみたい。

だから、単純にアタックされてるかのチェックにreCAPTCHAは優秀。実動においては別問題なので、体当たりでやっていきましょうねということになる。

結論として、今回導入した内容は間違ってなかったと言える。とにかく、対象サイトへのスパムが半角英数記号の文字列をぶち込んでくる、radioとかは選択してくる、「日本語を使わない」ってルールで動いてることが確かなので噛み合った。対日本のスパムだったらその辺やってきそうなもんだと思うんだけどね。どうなんでしょうね。

なので、もしreCAPTCHAを使いたくない・使えない環境だとしたら日本語縛りのバリデーションが使えるフォームを作って頑張りましょう。だからフリガナはとても重要な項目です。項目が少ないとシンプルでお洒落っぽいけど、自衛を考えたら必要になります。みたいなね。

コメント

タイトルとURLをコピーしました