reCAPTCHA完全に理解した

# はじめに
2024/08/01に、Google reCAPTCHAの価格改定・無料利用枠変更が実施されました。これに伴い、既存reCAPTCHAに対しても **10,000件/月** の利用制限が適用されます。
それ以前は**1,000,000件/月** だったため、無料利用可能回数が1/100になった、ということです。

10,000件の制限を超えると、reCAPTCHAが停止します。つまり、reCAPTCHAの認証に依存するコンテンツは、利用できなくなってしまいます。
この記事では、reCAPTCHAを使う開発者を支援するために、それぞれの概念を整理します。


# 注意
用語と仕様、それら理解は、2024/12/17時点のものです。Googleは不定期にネーミングや仕様を変更してくるため、ここに記載している内容がいまも正しいとは限りません。

# reCAPTCHAとは
Googleが提供する不正行為・不正使用対策ツールです。
ウェブサイトに組み込むことで、botからのアクセスをブロックしたり、アカウント乗っ取り対策などができます。
「私はロボットではありません」のチェックボックスが一番有名でしょうが、それらを表示せずサイレントに動くバージョンもあります。
https://cloud.google.com/security/products/recaptcha?hl=ja

# reCAPTCHAの違い紹介
私はここの理解でずっこけました。なので真剣に紹介します。
## 公式資料
https://cloud.google.com/recaptcha/docs/compare-tiers?hl=ja
（´-`）.｡oO（残念ながら、これではわからないことがたくさんありました）

## reCAPTCHA Classic（reCAPTCHA Lite）
もともと「reCAPTCHA」と呼ばれていたサービスです。v2 / v3のバージョンで機能が違います。
昔から（2020年以前まで？）無料でreCAPTCHAを使っている場合は、たぶんこれです。

:::note warn
いつまで登録された情報がreCAPTCHA Classicで、いつからreCAPTCHA Essentialsなのか、という説明はどこにも見つかりませんでした。
:::

無料で月10,000件まで使用可能です。それを超えると、停止します（翌月にリセットされます）
https://www.google.com/recaptcha/admin/
「reCAPTCHA 管理コンソール」で状況を確認できます。
Google Cloud管理画面でもキーは閲覧可能ですが、reCaptcha Enterpriseへのバージョンアップを求められます。
移行する際の手順は
https://cloud.google.com/recaptcha-enterprise/docs/migrate-recaptcha

この無料枠reCAPTCHAは「**reCAPTCHA Lite**」とリネームされる、とのことでしたが、2024/12/17現在もreCAPTCHA Liteの名前は出てきません。
https://internet.watch.impress.co.jp/docs/yajiuma/1565437.html

## reCAPTCHA Essentials
最近登録した人が無料で使えるreCAPTCHAです。
無料で月10,000件まで使用可能です。それを超えると、停止します（翌月にリセットされます）
https://www.google.com/recaptcha/admin/
「reCAPTCHA 管理コンソール」とGoogle Cloudの両方で作成可能ですが、Google Cloudで作成した場合は「reCAPTCHA 管理コンソール」では閲覧できません。

## reCAPTCHA Standard
reCAPTCHA Essentials状態のreCAPTCHAを、決済可能なGoogle Cloud(GCP)と紐づけると、reCAPTCHA Standard状態になります。
無料で月10,000件まで使用可能で、それを超えると課金対象になります。100,000件を超えると、reCAPTCHA Enterprise状態になります。

## reCAPTCHA Enterprise
課金版reCAPTCHAの最上位プランですが、機能はreCAPTCHA Standardと変化ありません（少なくとも比較表では、そのように見えます）
また、ドキュメント内では「reCAPTCHA Standard」と「reCAPTCHA Enterprise」の両方を「reCAPTCHA Enterprise」で表現されている場合があります。

# reCAPTCHAアカウントの罠
reCAPTCHAに課金を登録している場合、アカウント設定はGoogle Cloudで共有されます。
しかし無課金版（Classic / Essentials)の場合、個人間でしか共有されません。

無課金版reCAPTCHAはgmailに紐づいて管理されます。企業アカウントでも社員個人に紐づいてしまうため、それを嫌がって共用の無料gmailアドレスを作って運用する場合が**まれによくある**のですが、その場合に問題が生じます。
reCAPTCHA Classicが10,000件に達したときに、どこからも通知が来ないまま、機能停止してしまいます。

これを防ぐためには
- reCAPTCHA管理画面 https://www.google.com/recaptcha/admin/ で、複数人をオーナーに設定する
- Google Cloudで決済情報と紐づける

この二点が必要です。

# reCAPTCHA classicの罠
reCAPTCHA Classicは、無課金のまま停止したときに、そのままでは対応できません。
reCAPTCHA Essentialsは、Google Cloudの支払い情報を紐づければ、reCAPTCHA Standardとして稼働するため、月10,000件以上来ても動き続けます。しかし**reCAPTCHA Classicは支払い情報を紐づけることができません**。
Google Cloud管理画面からアップグレードすることで、reCAPTCHA Essentialsに変換されますが、先述の通り**ログインしている人が当該reCAPTCHAのオーナーでない限り、リストにも表示されません**。そのため、止まったことの検知自体が困難です。

# reCAPTCHA Enterpriseの罠
reCAPTCHA Enterpriseには二種類の実装方法があります。
Google Cloud内で紹介されているトークンを使った実装方法(以下新実装)と、旧reCAPTCHAページで紹介されている秘密鍵を使った方法(以下旧実装)です。
普通に「reCAPTCHA」で検索したときに出てくる実装はたいてい旧実装です。WordPressのプラグインの多くは、旧実装のキーで動きます。しかしGoogle Cloudの画面では新実装の手順が紹介され続けています。
また、旧実装状態で動いている**reCAPTCHA Classicのキーをアップグレードせず**、新規に作ったreCAPTCHA EssentialやStandardアカウントに差し替えたい場合に、旧実装で動かすためのキー情報がわかりづらい！！！

2024/12/17時点では
- reCAPTCHA通信をしていないキーの場合、「サードパーティーのサービスやプラグインと統合する」をクリックすると「以前のreCAPTCHA秘密鍵」が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9384/1f39cbca-eec5-ea99-27a1-4be8ef1bf18e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9384/a8298e52-9209-550a-bb3d-fcd4b89e5279.png)

- 何らかの形でreCAPTCHA通信をしているキーの場合、「以前の鍵を使用する」をクリックすると表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9384/191f2351-52d8-8f73-b6b7-e114ff63cd1a.png)
- reCAPTCHA 管理コンソールを開くと、キー情報が確認できます。
    - https://www.google.com/recaptcha/admin/

Google的には新実装に移動してほしいのはわかりますが、ちょっとこれはわかりにくいですね。

# reCAPTCHA Enterprise実装の罠
PHPのサンプルコード内で求められるライブラリのバージョンが非常に古く、Composerが依存関係の解決に失敗します。
これはREST APIで直に実装したほうがいいと思います。

# まとめ
私の理解でreCAPTCHAに関する概念をまとめましたが、reCAPTCHA自体はまだまだ進化し続ける機能のため、概念や仕様はこれからも変化していくことでしょう。
私が本当に **「reCAPTCHA完全に理解した」** 状態に至るのは、いつになるでしょうか……