この記事をシェアする

WordPressのログイン画面にreCAPTCHAを実装した

はじめに

過去の記事でも紹介しているように、当ブログではログイン画面へのセキュリティ対策として
ベーシック認証を導入している。

だがしかし、ログイン画面というのはサイトでもっとも重要な部分の一つ。
セキュリティは幾ら強固にしてもしたりないものである。
ここの守りを疎かにしてしまうと、何者かが不正にログインしたりしないか、
不安で不安で夜しか眠れなくなってしまうことだろう。

どこで、導入も比較的簡単でありつつ、スパム避けとしての実績も豊富な
Google reCAPTCHAをログイン画面に実装してみることにした。

①reCAPTCHA用のサイトキー・APIキーを取得する

Google reCAPTCHAを利用するためにはサイトキーと
APIキー(シークレットキー)が必要になる。
それを取得するために、以下のページにアクセス。

https://www.google.com/recaptcha/admin/create

色々種類があるけどここでは「私はロボットではありません」って奴を使う

そんなこんなでキーが発行されたので、こいつを使ってログインフォームに
reCAPTCHAをぶちこんでいく

②ログイン画面上にreCAPTCHAのチェックボックスを表示する

functions.phpに以下のように追記。

// フォームにチェックボックス(私はロボットではありません)を追加
add_action( 'login_form', 'add_recaptcha_for_login_form' );
function add_recaptcha_for_login_form() {
?>
<div class="g-recaptcha" data-sitekey="<?=RECAPTCHA_SITE_KEY;?>"></div>
<?php
}

// ログイン画面のhead内でJavaScript呼び出し
add_action( 'login_head', 'add_recaptcha_for_login_head' );
function add_recaptcha_for_login_head() {
?>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<?php
}


この状態でログイン画面にアクセス。
ちゃんとチェックボックスが表示されている模様。

デザインは盛大に崩れているので、気になる人はCSSで調整すると良いかも。

ただし、現状だとこのチェックボックスも単なるハリボテに過ぎない。
ここに更に処理を加えて、ちゃんとチェックを入れた人でないと
ログインできないようにしていく。

③reCAPTCHA実施結果判定処理の追加

フォームにreCAPTCHAを仕込むと、目には見えないがフォーム内に
「g-recaptcha-response」という名前のinput要素(正確にはテキストエリア)が追加される。
ユーザが「私はロボットではありません」にチェックを入れると、
この要素内にランダムな文字列がセットされる。

その文字列をGoogleのAPIに投げつけることで、
そのユーザがちゃんと「私はロボットではありません」にチェックを入れたかどうか
判定できるという寸法なのである。

※APIの詳細については下記参照

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

ログイン認証時に処理を追加したい場合、
「wp_authenticate_user」というフィルターが使えるようだ

そんなわけで、functions.phpに、curlによるAPI呼び出し処理と
結果に応じた分岐処理を追加。

add_filter('wp_authenticate_user', 'verify_recaptcha_response');
function verify_recaptcha_response ($user) {
    try {
        // フォームから受け取ったreCAPTCHAの検証結果
        $g_response = (string)filter_input(INPUT_POST, 'g-recaptcha-response');

        $post_data = [
            'secret' => RECAPTCHA_SEECRET_KEY,
            'response' => $g_response,
            'remoteip' => $_SERVER['REMOTE_ADDR'],
        ];
    
        $curl = curl_init(RECAPTCHA_API_URL);
        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($post_data));
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);  
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);  
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
    
        $recaptcha_result = curl_exec($curl);
        curl_close($curl);

        $recaptcha_result_array = json_decode($recaptcha_result, true);

        // 検証結果がダメダメだったら例外を投げる
        if ($recaptcha_result_array === null) {
            throw new \Exception('JSONがデコードできなかった');
        }
        if (!isset($recaptcha_result_array['success'])) {
            throw new \Exception('successがない');
        }
        if ($recaptcha_result_array['success'] === false) {
            throw new \Exception('不正なユーザーと判定');
        }

        return $user;

    } catch (\Exception $ex) {
        return new WP_Error('user_not_verified', 'recaptcha検証失敗:' . $ex->getMessage());
    } 
}

この状態で、「私はロボットではありません」をチェックせず
ログインを試みると…

想定通りのエラーメッセージが表示される

もちろん、ちゃんとチェックを入れさえすれば…

しっかりログインできる!

あとがき

reCAPTCHAについては過去に業務で何度か仕込んだこともあり、
WordPress独自の書き方さえ理解すれば実装は難しくなかった。

本当に手軽に実装できてなおかつ効果も実証されているので、
WordPressでサイトを運用している人は
是非導入にチャレンジしてもらいたい。

とはいえ、reCAPTCHAを入れればこれで一安心という訳ではない。
さらなるセキュリティ向上のため、まだまだいろんな手を打っていきたい所存である。

この記事をシェアする