16
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ZOZOテクノロジーズ #2Advent Calendar 2019

Day 22

Google reCAPTCHA v3をRuby On Railsに入れてみました〜

Last updated at Posted at 2019-12-21

reCAPTCHAとは

ボットなどによる悪質なアクセスからWebサイトを守るための機能です。
V2については以下の記事を参考してください。
https://qiita.com/amagasu1234/items/9760c2c410776fd02e12

今回はRubyOnRails環境でreCAPTCHA V3を追加してみました。

説明
V1 歪められた文字を読み取って入力することでボットではないことを確認する。 2018年3月サービス終了 スクリーンショット 2019-12-21 22.26.16.png
V2 画像を選択させることで人間とボットを判別する。 スクリーンショット 2019-12-21 22.47.58.png
V3 V1/V2とは違ってユーザー入力なし、アクセスに対する人間らしさのスコア値 (0.0 〜 1.0) でボット判別。 2018年10月29日サービス開始 スクリーンショット 2019-12-21 22.47.22.png

#開発環境
rails: 5.1
macOS Mojave
IDE: RubyMine
今回のテストソースは以下のrails チュートリアルをベースに実装したので詳細内容は以下のリンクを参照してください。
https://railstutorial.jp

ログイン画面にreCAPTCHAをテストするため、以下のrails チュートリアルのOpenソースを使いました。
https://github.com/yasslab/sample_apps

#作業手順

  1. Google reCAPCHA管理コンソールからサイトキーとシークレットキー取得
  2. ヘッダーにreCAPTCHAのスクリプト追加
  3. ログインフォームにHidden追加
  4. サーバーサイド実装

#Google reCAPCHA管理コンソール

新規登録

以下のリンクから新規登録するとサイトキーとシークレットキーが発行されますので覚えておきましょう。
https://www.google.com/recaptcha/admin/create
スクリーンショット 2019-12-21 23.04.16.png

登録完了

登録が完了すると以下のような不正リクエストの状況を確認できる管理サイトが追加されます。
スクリーンショット 2019-12-21 23.07.26.png

#ヘッダーにreCAPTCHAのスクリプト追加

application.html.erb
<script src="https://www.google.com/recaptcha/api.js?render=reCAPCHAサイトキー"></script>
<script>
        grecaptcha.ready(function () {
            grecaptcha.execute('reCAPCHAサイトキー', { action: 'contact' }).then(function (token) {
                var recaptchaResponse = document.getElementById('recaptchaResponse');
                recaptchaResponse.value = token;
            });
        });
</script>

#ログインフォームにHidden追加
ログイン画面にHidden追加
<input type="hidden" name="recaptcha_response" id="recaptchaResponse">

sessions/new.html.erb
<% provide(:title, "Log in") %>
<h1>Log in</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_for(:session, url: login_path) do |f| %>
      <%= f.label :email %>
      <%= f.email_field :email, class: 'form-control' %>

      <%= f.label :password %>
      <%= link_to "(forgot password)", new_password_reset_path %>
      <%= f.password_field :password, class: 'form-control' %>

      <%= f.label :remember_me, class: "checkbox inline" do %>
        <%= f.check_box :remember_me %>
        <span>Remember me on this computer</span>
      <% end %>
      <input type="hidden" name="recaptcha_response" id="recaptchaResponse">

      <%= f.submit "Log in", class: "btn btn-primary" %>
    <% end %>

    <p>New user? <%= link_to "Sign up now!", signup_path %></p>
  </div>
</div>

#サーバーサイド実装

SessionsController
require 'uri'
require 'net/http'

class SessionsController < ApplicationController

  RECAPTCHA_SECRET_KEY = 'reCAPTCHAコンソールからシークレットキーを入力'
  RECAPTCHA_SITEVERIFY_URL = 'https://www.google.com/recaptcha/api/siteverify'

  # POST /login
  def create
    # siteverifyAPIを呼び出してボットかチェック
    siteverify_uri = URI.parse("#{RECAPTCHA_SITEVERIFY_URL}?response=#{params[:recaptcha_response]}&secret=#{RECAPTCHA_SECRET_KEY}")
    response = Net::HTTP.get_response(siteverify_uri)
    json_response = JSON.parse(response.body)

    # reCAPTCHAのレスポンスデータが成功かスコアが0.5以上なら人間のアクションだと判断
    # スコアについては運用中変更する必要がある
    if json_response['success'] && json_response['score'] > 0.5
      user = User.find_by(email: params[:session][:email])
      if user && user.authenticate(params[:session][:password])
        if user.activated?
          # Success
          log_in user
          params[:session][:remember_me] == '1' ? remember(user) : forget(user)
          redirect_back_or user
        else
          message  = "Account not activated. "
          message += "Check your email for the activation link."
          flash[:warning] = message
          redirect_to root_url
        end
      else
        # Failure
        flash.now[:danger] = 'Invalid email/password combination'
        render 'new'
      end
    else
      flash.now[:danger] = '不正アクセスです。'
      render 'new'
    end
  end

end

siteverifyAPIが返すscoreが「1」に近いのがより人間のアクション、「0」に近い場合はボットの可能性が高い意味です。

これだけでGoogle reCAPTCHAが画面からのアクションを監視します。
以下の画面の右下にreCAPTCHAに保護されているのが表示されます。
スクリーンショット 2019-12-21 23.21.55.png

3人のアカウントを事前に登録してアカウントを変えてログインしたら最初ログインに成功したユーザー以外のアカウントではログインできませんでした。

#まとめ
こんなに簡単にボットからサイトを守れるのはすごい、問題はどれぐらい正確に判断できるのかですね。
今回は実装だけやってみましたが次回はCapybaraを利用してテストしてみます。

16
12
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?