3
1

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 1 year has passed since last update.

AutifyAdvent Calendar 2021

Day 17

reCAPTCHA v3 に対して Autify でテスト自動化してみた

Last updated at Posted at 2021-12-17

この記事は Autify アドベントカレンダー2021 の17日目のエントリです。

こんにちは! Autify カスタマーサポートエンジニアの hiroxyy です。
Qiita 初投稿となる本エントリでは、 reCAPTCHA v3 が導入されているサイトに対して Autify でテストを実行したらどうなるのか、その結果をまとめました。

reCAPTCHA v3 とは

Google が提供している、人間と bot を識別するための API です。
以下のような特徴があります。

  • サイトに訪問したユーザーにチェックボックスのチェックや文字識別のアクションを求めないため、ユーザビリティを低下させない
  • API が返却するスコア(0.0 ~ 1.0)に応じてどう処理するかを、 サイト側で実装する必要がある
  • サイトへのアクセスが増えるほど、API は学習し返却するスコアもそれに基づき変わる

また以下の公式の FAQ には、過去のバージョンである reCAPTCHA v2 とどちらを使うべきかについても触れられています。
Should I use reCAPTCHA v2 or v3? | Google Developers

reCAPTCHA v3 is for site owners who want more data about their traffic. For more information, see the reCAPTCHA v3 developer guide.
We support security and usability for v2.

こっちを使うべし!とは記載されていないので、 Google としては必要に応じて v2, v3 を使い分けてくれ、といった感じになるんでしょうか。
古いバージョンである v2 に対してもサポートすることが明示されており、 v2 が廃止予定ということもなさそうですね!

v2 と v3 の違いをより詳しく知りたい方は、個人的に以下記事がわかりやすくてオススメです!
reCAPTCHA v2 と v3 の違い - Qiita

reCAPTCHA v3 の導入

今回は Ruby on Rails チュートリアルのサンプルアプリケーションのログインページに導入してみました。
M1 Mac 上で初めて Rails アプリケーションを動かしたので、reCAPTCHA v3 の実装以外にも、環境構築になかなか時間を取られました。
環境構築ツライ:innocent:

実装に関しては、 Google reCAPTCHA v3をRuby On Railsに入れてみました〜 - Qiita を参考にしました。
具体的なコードは↓↓です。

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

application.html.erb
<script src="https://www.google.com/recaptcha/api.js?render=reCAPCHAサイトキー"></script>

ログインフォームに Hidden と、ボタンクリック時の処理を追加

grecaptcha.execute によって生成されるトークンの有効期限は2分です。
Placement on your website | Google Developersに記載があるように、ページロードではなくユーザーのアクションが実行されたタイミングでトークンを生成するようにしましょう。
仮にページロード時にトークンを生成すると、ユーザーのアクション前にトークンが切れてしまい reCAPTCHA v3からスコアが正常に返却されない問題が起き得ます:warning:

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_with(url: login_path, scope: :session, local: true, id: "form") 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 %>
      <%= f.submit "Log in", class: "btn btn-primary", id: "login" %>
      <input type="hidden" name="recaptcha_response" id="recaptchaResponse">
    <% end %>

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

<script>
$("#login").on("click", function(e) {
  // データ送信をSTOP
  e.preventDefault();
  // reCAPTCHA tokenを生成
  grecaptcha.execute('reCAPCHAサイトキー', { action: 'login' }).then(function (token) {
    var recaptchaResponse = document.getElementById('recaptchaResponse');
    recaptchaResponse.value = token;
    // フォームを送信
    document.getElementById("form").submit()
  });
});
</script>

reCAPTCHA v3 からスコアを受け取り bot の判定処理を追加

今回はInterpreting the score | Google Developers の記載に従い、 0.5 を 人間と bot のしきい値として利用しました。

class SessionsController < ApplicationController

  RECAPTCHA_SECRET_KEY = 'reCAPTCHAシークレットキー'
  RECAPTCHA_SITEVERIFY_URL = 'https://www.google.com/recaptcha/api/siteverify'

  def new
  end

  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)

    # scoreの保存
    session[:score] = json_response['score']

    # reCAPTCHAのレスポンスデータが成功かスコアが0.5以上なら人間のアクションだと判断
    # スコアについては運用中変更する必要がある
    if json_response['success'] && json_response['score'] > 0.5
      user = User.find_by(email: params[:session][:email].downcase)
      if user && user.authenticate(params[:session][:password])
        if user.activated?
          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
        flash.now[:danger] = 'Invalid email/password combination'
        render 'new'
      end
    else
      flash.now[:danger] = "不正アクセスです。score: #{json_response['score']}"
      render 'new'
    end
  end

  def destroy
    log_out if logged_in?
    redirect_to root_url
  end
end

Autify を利用し、ログイン操作のテスト自動化

そもそも、reCAPTCHA v3 が組み込まれているページにテストすることは想定されているのでしょうか。
その答えは公式のFAQにありました!

For reCAPTCHA v3, create a separate key for testing environments. Scores may not be accurate as reCAPTCHA v3 relies on seeing real traffic.

テスト環境用のキーを作成し、それを利用してくださいとありますね。
今回は個人のお試しアプリケーションなのでテスト環境用のキーはないですが、実際はテスト環境用にキーを分けて、しきい値を 0.0 にして bot としてはじかれないようにした方がテスト自動化の観点だと楽そうですね😋

今回は Autify で以下のようなログイン操作と、その際の reCAPTCHA v3 から返却されるスコアがどうなっているかを確認するテストを作成してみました。
ログイン_with_reCAPTCHA_v3_-_Autify.png

bot と判定されたらステップ6でログインページに戻されるので、テストが失敗するような作りになっています。
また、bot と判定されなくてもその時のスコアの値がどうなっているのかも確認したいので、ステップ7でスコアを確認するステップを追加しています。

実行結果

複数の実行環境で繰返しテストを実行したところ、テストを実行する毎にスコアが下がっていく実行環境があることがわかりました!
実際の、各環境における実行回数毎のスコアの変動を表にまとめています。
赤文字はしきい値を下回り bot 判定されたテスト実行です。

テストを実行したブラウザ / OS 1回目 2回目 3回目 4回目
Safari 14.0 / macOS Big Sur 0.9 0.9 0.9 0.7
IE 11.0 / Windows 10 0.9 0.9 0.9 0.9
IE 11.0 / Windows Server 2019 0.9 0.9 0.9 0.7
Firefox 93.0 / macOS Big Sur 0.9 0.9 0.9 0.9
Firefox 93.0 / Windows 10 0.9 0.9 0.9 0.9
Edge 95.0 / Windows 10 0.9 0.9 0.9 0.7
Edge 95.0 / Windows Server 2019 0.9 0.9 0.7 0.7
Chrome 95.0 / macOS Big Sur 0.9 0.9 0.9 0.7
Chrome 95.0 / Windows 10 0.9 0.9 0.9 0.3
Chrome 95.0 / Linux 0.9 0.9 0.7 0.3

Firefox のスコアの高さがすごいw
サイトへのアクセスが増えるにつれて reCAPTCHA v3 が学習し、返却されるスコアが変わっているのがわかりますね。
実行回数がまだまだ少ないので、今後もどんどん変わりそうな予感がします。

まとめ

  • reCAPTCHA v3 は人間か bot かを判定するためのスコア(0.0 ~ 1.0)を返すのみ。スコアに基づいてどう処理するかはサイト側で実装が必要になる
  • テスト環境用に reCAPTCHA v3のキーを分けて運用したほうが良い
  • reCAPTCHA v3 が組み込まれたサイトに対して Autify でテストを実行した場合、reCAPTCHA v3 から返却されるスコアはテストの実行環境や、サイトへのアクセス数によってばらつきが出る
  • テスト環境の場合は、 bot かどうか判別するしきい値に 0.0 を設定しておくことでテストの失敗を回避可能
  • 本番環境の場合は、固定IPアドレス機能を利用し Autify からのアクセス時は reCAPTCHA v3 による処理を実行しないようにすることでテストの失敗を回避可能

おまけ

Autify によるログインではなく、手動で色んな方法でログインした時にスコアがどうなるか試してみました。
サイトのアクセス数によってスコアは変わるので、あくまで参考です。
調べてみると reCAPTCHA v2・v3 API のレスポンスがわかるデモサイトもあったので、遊んでみるとけっこう楽しいです👍

  • Chrome のゲストモードでログイン: 0.9
  • Chrome のシークレットモードでログイン: 0.9
  • Chrome のモバイルエミュレートを利用し、iPhone Xでログイン: 0.9
  • Chrome のモバイルエミュレートを利用し、カスタムデバイスでログイン: 0.9
  • Chrome のユーザーエージェントを Goolebot にしてログイン: 0.9
  • Chrome のユーザーエージェントを Chrome / Windows にしてログイン: 0.9
  • Chrome のユーザーエージェントを hogehoge にしてログイン: 0.9
  • Chrome の Network throttling を Slow 3G にしてログイン: 0.9

自分が試した範囲では見事に全て 0.9 となり、人間判定されています🎊

個人的にはどのようにスコアが計算されているのかは私達にはわかりようがないので、 reCAPTCHA v3 だけに頼るのは怖いなぁという感じがします。
かといって強固にしすぎてユーザビリティを損ねたくもないので、 bot をはじくための実装はまだまだ奥が深そうだと知ることができ、非常に勉強になりました🖌

3
1
0

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
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?