はじめに
過去の記事でも紹介しているように、当ブログではログイン画面へのセキュリティ対策として
ベーシック認証を導入している。
だがしかし、ログイン画面というのはサイトでもっとも重要な部分の一つ。
セキュリティは幾ら強固にしてもしたりないものである。
ここの守りを疎かにしてしまうと、何者かが不正にログインしたりしないか、
不安で不安で夜しか眠れなくなってしまうことだろう。
どこで、導入も比較的簡単でありつつ、スパム避けとしての実績も豊富な
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
}
この状態でログイン画面にアクセス。
ちゃんとチェックボックスが表示されている模様。
ただし、現状だとこのチェックボックスも単なるハリボテに過ぎない。
ここに更に処理を加えて、ちゃんとチェックを入れた人でないと
ログインできないようにしていく。
③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を入れればこれで一安心という訳ではない。
さらなるセキュリティ向上のため、まだまだいろんな手を打っていきたい所存である。