Rails に reCAPTCHA v3 導入して bot 対策
概要
Rails で構築した Web サービスで bot 攻撃を定期的に受けた為、問い合わせフォームに reCAPTCHA v3 を導入しました。
何故 v2 でなく、reCAPTCHA v3 ?
v2 は I'm not a robot
チェックボックスにチェックを入れた後に画像選択させる仕様があります。
例えば、看板が写ってるのはどれ?と選ばせる問いが出てきた場合、
「どこまでが看板としたらいいの?」と心理的負担も高く、ユーザが離脱する可能性もあります。
v3 だと嬉しいことは何?
v3 *1 は設置したページのユーザ行動をスコア化し bot か判断します。
アクセスが増えるとより精度が高まってくる、という仕様です。
非 bot ユーザへの負担は全くなく、 bot を遮断できる様になるという、世の中進んでるなぁ感満載です。
gem ある?
今回 gem は使用しませんでした。
というのも、 以下理由からでした。
gem 'recaptcha'
が v3 非対応。gem 'new_google_recaptcha'
は v3 対応してますが、スコアが返ってこないのでテストし辛い。
その他に既にあるのかもわかりませんが、記事執筆時には探し出すことはできませんでした。
まず reCAPTCHA v3 発行
以下 reCAPTCHA コンソールにアクセスし発行してください。
v3 を選択し、今回導入するドメインを登録します。*2
発行されたサイトキー・シークレットキーを保存しておきます。
- サイトキー
- ユーザがサイトにアクセスした際にトークンを取得する際に必要なキーです。こちらはユーザ公開して問題ありません。
- シークレットキー
- トークンを元に Google に問い合わせする際に必要なキーです。こちらは秘密情報として扱います。
Rails 側実装
Rails >= 5.2 を想定しています。
config/credentials.yml.enc
recaptcha:
secret_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
シークレットを秘密情報に保存します。
app/controllers/application_controller.rb
require 'net/http' require 'uri' class ApplicationController < ActionController::Base ... RECAPTCHA_MINIMUM_SCORE = 0.5 RECAPTCHA_ACTION = 'homepage' ... def verify_recaptcha?(token) secret_key = Rails.application.credentials.recaptcha[:secret_key] uri = URI.parse("https://www.google.com/recaptcha/api/siteverify?secret=#{secret_key}&response=#{token}") r = Net::HTTP.get_response(uri) j = JSON.parse(r.body) j['success'] && j['score'] > RECAPTCHA_MINIMUM_SCORE && j['action'] == RECAPTCHA_ACTION end end
共通メソッドとして、recaptcha の認証メソッド `verify_recaptcha?` を設定しています。
ここで、bot となるスコアを 0.5 以下としています。
通常通り操作していれば、十分超える数値です。
config/locales/en.yml
en: recaptcha: errors: verification_failed: 'reCAPTCHA Authorization Failed. Please try again later.'
local en 設定です。
config/locales/ja.yml
ja: recaptcha: errors: verification_failed: 'reCAPTCHA 認証失敗しました。しばらくしてからもう一度お試しください。'
local ja 設定です。
app/controllers/hoges_controller.rb
class HogesController < ApplicationController def new; end def create unless verify_recaptcha?(params[:recaptcha_token]) flash.now[:recaptcha_error] = I18n.t('recaptcha.errors.verification_failed') return render action: :new end # something to do redirect_to hoge_finish_path end def finish; end end
new から create に post して reCAPTCHA で bot 判定して
- OK → finish へ進む
- NG → new に戻る
という設計です。
app/views/hoges/new.html.erb
<% if flash[:recaptcha_error] %> <div class="text"> <p><spacn class="error"><%= flash[:recaptcha_error] %></span></p> </div> <% end %> <%= form_tag({action: :create}, {method: :post}) do %> ... <input id="recaptcha_token" name="recaptcha_token" type="hidden"/> <%= submit_tag "送信する", :class => "submit-recaptcha btn", :disabled => true %> <% end %> <script src="https://www.google.com/recaptcha/api.js?render=<%= Settings.recaptcha.site_key %>&ver=3.0"></script> <script> grecaptcha.ready(function() { grecaptcha.execute('<%= Settings.recaptcha.site_key %>', {action: 'homepage'}).then(function(token) { $('#recaptcha_token').val(token); $('.submit-recaptcha').prop('disabled', false); }); }); </script>
エラーメッセージ表示
<% if flash[:recaptcha_error] %> <div class="text"> <p><spacn class="error"><%= flash[:recaptcha_error] %></span></p> </div> <% end %>
<form> ~ </form>
内に以下 name=recaptcha_token
input タグを追加します。
<input id="recaptcha_token" name="recaptcha_token" type="hidden"/>
ページアクセス時に reCAPTCHA の token を取得すべく、スクリプトを仕込みます。
<script src="https://www.google.com/recaptcha/api.js?render=<%= Settings.recaptcha.site_key %>&ver=3.0"></script> <script> grecaptcha.ready(function() { grecaptcha.execute('<%= Settings.recaptcha.site_key %>', {action: 'homepage'}).then(function(token) { $('#recaptcha_token').val(token); $('.submit-recaptcha').prop('disabled', false); }); }); </script>
reCAPTCHA トークン取得が成功した場合に以下実行します。
- id="recaptcha_token" input タグの value に トークンを設定
- submit ボタンの有効化
`<%= Settings.recaptcha.site_key %>` について
`gem 'settingslogic'` をインストールしている前提で設定しています。
導入していない場合は、簡易的に処理を試す程度であれば、 `<%= Settings.recaptcha.site_key %>` を取得したサイトキーに置き換えて下さい。*3
以上で設定は完了です。
ページにアクセスしてみる
ページ右下に reCAPTCHA マークが常に表示される様になります。
集計情報を見る
reCAPTCHA コンソールを見ると、以下の様な表示が出ていてすぐには集計情報が反映されていないと思います。
しばらく経つと以下の様なグラフが表示される様になります。
注意
例えば、社内 IP 等固定された IP からテストで頻繁にアクセスすると、 bot 扱いされます。
reCAPTCHA 側で IP のホワイトリストはないので、その場合、 Rails 側で許可 IP リストを作る必要があります。
以上
参考になれば幸いです。
Rails に reCAPTCHA v3 導入して bot 対策
https://kenzo0107.github.io/2019/02/16/2019-02-17-rails-recaptcha-v3-bot/