🦒

reCAPTCHA Enterpriseのスコアベースのキーの保護を使ってみた

2023/11/29に公開

はじめに

こんにちは、クラウドエース バックエンドディビション所属の廣瀬です。
reCAPTCHA Enterprise のスコアベースのキーを用いたリクエストの保護に関する技術に触れる機会がありました。
その際に学習した実装方法と動作検証について本記事では記載します。

本記事で記載すること

  • reCAPTCHA Enterprise の概要の説明
  • reCAPTCHA Enterprise のスコアベースのキーの保護の実装方法の解説
  • スコアベースのキーの保護の動作検証

reCAPTCHA Enterprise とスコアベースのキーの保護とは

reCAPTCHA Enterprise とは

reCAPTCHA Enterprise は、自動化された攻撃からウェブサイトやモバイルアプリを保護する Google Cloud のセキュリティツールです。
Bot などによる自動化ツールやスパム、人間による不正アクセスからアプリケーションを保護するだけでなく、認証情報のスタッフィング、アカウントの乗っ取り、自動アカウント作成などの不正行為も検出できます。
reCAPTCHA Enterprise により、ウェブサイトはさまざまな脅威から守られ、安全な運用稼働が可能となります。

reCAPTCHA Enterprise と同様にアプリケーションの不正行為の検出を行う reCAPTCHA と呼ばれる Google プロダクトがあります。
次の項で reCAPTCHA との違いを見ていきます。

reCAPTCHA との違い

機能 reCAPTCHA Enterprise reCAPTCHA
目的 企業レベルのウェブサイトとアプリケーションの保護 一般的なウェブサイトの保護
使用シナリオ 高度なセキュリティリスクと自動化された攻撃の防止 スパムと自動化されたアクセスの防止
料金体系 1,000 回評価あたり 1 ドル
(1 か月あたり最大 100 万評価まで無料)
無料
1 か月あたり最大 100 万評価を超える場合、
Google へリクエストする必要あり)
サポートレベル Google Cloud のサポート 基本的なサポート
サポートする保護機能 CAPTCHA チャレンジによる不正アクセスの保護
スコアベースのキーによる不正アクセスの保護
WAF での保護
多要素認証(MFA)のサポート
パスワード漏洩の検出
アカウント防御
CAPTCHA チャレンジによる不正アクセスの保護
サポートするプラットフォーム ウェブ
モバイル アプリ
WAF
ウェブのみ
スコアの粒度 11 レベル 4レベル
SLA 99.9% 以上の稼働率 該当なし

reCAPTCHA チャレンジとスコアベースのキーによる保護方法の違い

reCAPTCHA チャレンジとは

reCAPTCHA チャレンジによる不正アクセスの保護とは、皆さんがウェブサイトでよく見る以下のようなチェックボックスによる保護のことを指します。
ユーザーがロボットではないことを証明するためにクリックを要求し、その操作方法を判断して、不正なアクセスではないかを判定します。

スコアベースのキーの保護とは

スコアベースのキーの保護とは、ユーザーがチェックボックスを押下するなどの特別な操作なしで、画面上で行った操作が正当かどうかを確認する保護方法となります。

スコアベースのキーの保護の利点

reCAPTCHA チャレンジによる保護の場合、ユーザーに追加操作を要求することが必要なため、ユーザーの負担を増加させ、コンバージョン率が低くなる可能性があります。

スコアベースのキーの保護を利用することで、ユーザーに追加の操作を要求することなく、高品質な防御を実現することができます。

スコアベースのキーの保護による評価までのフロー

ログイン処理を例としたスコアベースのキーの保護による操作の評価判定までのフロー図は以下の通りとなります。

reCAPTCHA Enterprise のウェブサイトのスコアベースのキーの保護の実装方法

reCAPTCHA Enterprise のウェブサイトのスコアベースのキーの保護の実装方法の解説を行います。

なお、バックエンドは Golang を使用し、Golang 用のクライアントライブラリを利用して、操作に対する評価処理を解説します。

API の有効化と IAM ロールの付与

以下の API の有効化します。

また、キーの作成等を行うため、reCAPTCHA Enterprise の管理を行うユーザーへ以下の IAM ロールを付与します。

  • reCAPTCHA Enterprise 管理者(roles/recaptchaenterprise.admin)

スコアベースのキーの作成

ウェブ用のスコアベースのキーをgcloud recaptcha keys creatで作成します。コンソールでも作成可能です。
以下のコマンドは、linux/CloudShell 用のものなので、windows 等のコマンドはこちらで確認してください。

gcloud recaptcha keys create \
        --web \                            # ウェブ用のキーであると設定
        --display-name={DISPLAY_NAME}  \   # キーの表示名
        --integration-type=score \         # キーの種類、スコアベースなためscoreを設定
        --domains={DOMAIN_NAME}            # ウェブサイトのドメインまたはサブドメイン

正常にキーが作成できると、キー ID が返却されるので、ローカルに保存します。

スコアベースのキーをウェブサイトへ統合する

サンプル実装のソースはこちらにあります。

キー ID の統合

<head></head> 要素 に、スコアベースのキーのキー ID を含めたスクリプトを配置します。

<head>
  <script
    src="https://www.google.com/recaptcha/enterprise.js?render={キーIDを設定}}"
    async
    defer
  ></script>
</head>

トークンの取得と送信(フロー図の 2,3 の処理)

評価を行いたい操作(ログイン情報の送信や、フォームの送信)に、以下の処理を組み込み、操作に対するトークンを取得し、バックエンドへの API のリクエストへ含めます。

  1. grecaptcha.enterprise.readyによる reCAPTCHA ライブラリの準備
  2. grecaptcha.enterprise.executeによるトークンの生成

トークンの生成の際には、アクション名を指定します。アクション名を指定することで、評価する操作に対してグルーピングすることができ、コンソール画面にて、サイトをどの様に使用しているか把握することができます。

<script>
    // ログイン処理やフォーム送信処理等の評価したい操作のイベント処理
    document.getElementById("loginForm").addEventListener("submit", function (event) {
            event.preventDefault();
            grecaptcha.enterprise.ready(async () => {
                // トークンの取得(キーIDとアクション名を設定)
                const token = await grecaptcha.enterprise.execute('{キーIDを設定}', {action: '{アクション名を設定.例えばloginとか}'});
                // トークンを含めて、操作に対するリクエストをバックエンドへ送信
            });
        });
</script>

バックエンドで操作に対する評価を取得する

golang の reCAPTCHA Enterprise のライブラリを用いて、評価の取得を行います。

評価の作成(フロー図の 4 の処理)

フロントエンドから送られてきたリクエストに含まれるトークンを用いて、操作に対する評価を取得します。
サンプル実装のソースはこちらにあります。

import (
	"context"
	"fmt"
	"time"

	recaptcha "cloud.google.com/go/recaptchaenterprise/v2/apiv1"
	recaptchapb "cloud.google.com/go/recaptchaenterprise/v2/apiv1/recaptchaenterprisepb"
)

type Client struct {
	ProjectID  string // Google CloudのプロジェクトID
	SiteKey    string // reCAPTCHAのキーID
}

// CreateAssessment reCAPTCHA Enterpriseからトークンに対する評価を取得する関数
func (c Client) CreateAssessment(ctx context.Context,
    token string,            // フロントエンドから送信されたトークン
    recaptchaAction string,  // アクション名
    ) (*recaptchapb.RiskAnalysis, error) {
	// reCAPTCHA クライアントを作成する。
	client, err := recaptcha.NewClient(ctx)
	if err != nil {
		return nil, err
	}
	defer client.Close()

	// 追跡するイベントのプロパティを設定する。
	event := &recaptchapb.Event{
		Token:   token,
		SiteKey: c.SiteKey,
	}

	assessment := &recaptchapb.Assessment{
		Event: event,
	}

    // 評価リクエストを作成する。
	request := &recaptchapb.CreateAssessmentRequest{
		Assessment: assessment,
        // プロジェクト名を設定。フォーマットは必ず"projects/%s"とする。
		Parent:     fmt.Sprintf("projects/%s", c.ProjectID),
	}

    // 評価を取得
	response, err := client.CreateAssessment(
		ctx,
		request)

	if err != nil {
		return nil, err
	}
    :
    // 評価結果を返す
	return response.RiskAnalysis, nil
}

評価の判定(フロー図の 5 の処理)

上記の golang のコードで取得した評価については、以下の構造体で評価結果が返ってきます。

評価の判定に使用する主要なプロパティを見ていきます。

プロパティ 名前 説明
Assessment.RiskAnalysis.Score スコア 操作に対するスコア。0.0~1.0 までの範囲のスコアが設定され、高いほどリスクが低く正当な操作であると示します。詳細はこちらに記載があります。
Assessment.RiskAnalysis.Reasons 理由コード 一部の評価は、reCAPTCHA Enterprise が操作に対してどの様に解釈したかについて、詳細情報を出力してくれます。コードについてはこちらを参照してください。

バックエンドに対して送信されたリクエストに対して、取得したスコアと理由コードの結果により、バックエンドで保護する処理を行います。
例えば以下の処理判定を行います。

  • ログイン処理のリクエストのスコアが、低かった場合、不正な操作であると判定し、確認のため多要素認証による追加認証をしてもらう。
  • SNS のコメント送信のリクエストの理由コードがTOO_MUCH_TRAFFIC(トラフィック量が通常よりも多い)である場合、自動ツールによる DoS 攻撃と判定し、リクエストを拒否する。

スコアベースの保護の検証

検証するアプリケーションの説明

検証に使用するアプリケーションのソースコードはこちらにあり、アプリケーションの概要は以下の通りとなります。

  • ローカル上で構築(docker-compose)
  • ログインフォームのみのシンプルなフロント-バックエンドなアプリケーション
  • 以下のログイン操作に対する reCAPTCHA Enterprise のスコアベースの保護を行なっています。
    • Login ボタンを押下して、ログイン処理のリクエストをサーバーへ送信

検証の観点

各検証方法の操作に対して、reCAPTCHA Enterprise の以下の評価プロパティの結果について検証を行いました。

検証方法

1.正規ユーザーの行動を模倣するテスト

方法
  • Chrome で実施
  • 通常の使用パターン(ページ遷移/ログインフォーム入力/送信)でサイトを操作する。
  • 上記の使用パターンを 10 回行う。

結果

10 回行った操作に対して全て以下の結果でした。

  • スコア: 0.9
  • 理由コード: LOW_CONFIDENCE_SCOREのみ

2. 速度の速い操作のテスト

方法
  • Chrome で実施
  • 自動化ツール(Selenium)を使用。
  • 通常パターンの操作を自動化したスクリプトで素早く操作する。
  • 上記のスクリプトを間隔を空けて 10 回実行する。
結果

10 回行った操作に対して全て以下の結果でした。

  • スコア: 0.9
  • 理由コード: LOW_CONFIDENCE_SCOREのみ

3. 高頻度のリクエストのテスト

方法
  • Chrome と Firefox で実施
  • 自動化ツール(Selenium)を使用。
  • 通常パターンの操作を自動化したスクリプトで素早く操作する処理を用意
  • 上記スクリプトを、短時間で 100 回実行
結果

各ブラウザごとに 100 回リクエストした結果、スコアと理由コードの組み合わせで出力された数は以下の結果でした。
※可読性のため、LOW_CONFIDENCE_SCORE は省略しています。

  • Chrome

    スコア 理由コード
    0.9 [] 1
    0.9 [TOO_MUCH_TRAFFIC UNEXPECTED_USAGE_PATTERNS] 65
    0.9 [UNEXPECTED_USAGE_PATTERNS] 11
    0.1 [TOO_MUCH_TRAFFIC UNEXPECTED_USAGE_PATTERNS] 22
    0.1 [UNEXPECTED_USAGE_PATTERNS] 1
  • Firefox

    スコア 理由コード
    0.9 [] 1
    0.9 [TOO_MUCH_TRAFFIC UNEXPECTED_USAGE_PATTERNS ] 70
    0.9 [UNEXPECTED_USAGE_PATTERNS ] 6
    0.1 [TOO_MUCH_TRAFFIC UNEXPECTED_USAGE_PATTERNS ] 23

検証結果について考察

今回は通常時のトラフィック量が足りない状態での検証となり、もしトラフィック量が増えれば異なる検証結果になる可能性があります。
参考程度に本検証の考察を確認いただければと思います。

  • 正規ユーザーの操作は期待通り正常な操作として認識する傾向がある
    正規ユーザーの行動の操作では、問題のない操作(スコアが0.9)であると認識された結果であり、期待通りの判定内容でした。

  • 速度の速い操作は、間隔を空ければ正常な操作であると認識する傾向がある
    自動化ツールを使用した速度の速い操作についても、問題のない操作と判定した結果でした。
    なので、操作間隔の空いた通常パターンの操作については正常な操作として認識する傾向があるのかと推測できます。
    一般的なユーザーでも、一定の間隔を開けて画面操作を連続する行動(パスワードを間違えてログインするなど)はあると思いますので、ユーザー行動に基づいた正しい判定が返されているのではないかと思われます。

  • DDoS 攻撃の様な高頻度のリクエストは、不正なアクセスとして認識する傾向がある
    高頻度のリクエストのテストは、DDoS 攻撃のような大量のリクエストに対する評価の結果は、ブラウザ間の違いはほとんどなく、以下のパターンに分かれました。

    • スコアが 0.9、理由コードが LOW_CONFIDENCE_SCOREのみ
    • スコアが 0.9、理由コードが UNEXPECTED_USAGE_PATTERNS
    • スコアが 0.9、理由コードが TOO_MUCH_TRAFFICLOW_CONFIDENCE_SCORE
    • スコアが 0.1、理由コードが UNEXPECTED_USAGE_PATTERNS
    • スコアが 0.1、理由コードが TOO_MUCH_TRAFFICLOW_CONFIDENCE_SCORE

    理由コードのUNEXPECTED_USAGE_PATTERNSは「サイトの操作が、想定したパターンと大きく異なっている」。TOO_MUCH_TRAFFICは「トラフィック量が通常よりも多い」と操作に対して reCAPTCHA Enterprise が解釈したとする結果となっており、両コードは Bot 等による不正な操作が行われていると解釈される結果となります。

    スコアが高い場合がありますが、不正な操作であると認識する回数が大半を占める結果となり、高頻度のリクエストの場合は、不正なアクセスとして認識する傾向があるとわかりました。

    スコアと理由コードの関係を考察すると、「スコアは高いが理由コードが不正操作と解釈される」パターンと、「スコアは低く、理由コードが不正操作と解釈される」パターンで分けられ、両出力は相関関係にはなく独立した判定なのだと考えられます。

    そのため、ログイン処理でスコアベースの検証を行う際には、スコアと理由コードの 2 つを参照し、スコアが低い場合と理由コードが不正と解釈した場合は、ログイン処理を中断させることや MFA などによる追加認証の要求を求める処理を行うのが良いと思われます。

まとめ

今回は、reCAPTCHA Enterprise のスコアベースのキーの保護について実装方法と検証した結果についてまとめました。
スコアベースのキーの保護は、reCAPTCHA チャレンジと比べて、正規ユーザーに負担がかからず、不正なアクセスを保護でき、かつ導入も簡単であることがメリットであると思います。

reCAPTCHA Enterprise はスコアベースのキーの保護の他に、WAF へ統合することができたり、パスワードの漏洩を検出する機能もありますので、機会があればこちらも実装、検証をしてみたいと思います。

Discussion