Google reCAPTCHA v2の設定をしてみた

# はじめに
とある日からお問合せフォームからスパムメールが大量に送られてくるようになりました。
qq.comのドメインから中国後で書かれた解読不能なメールが1分間に何10件も、、、

その対策として導入したキャプチャ認証のreCAPTCHAを入れてからスパムメールはピタリと止まりました。
今回はそのreCAPTCHAの設定方法の共有記事になります。

# やること
おおまかにですが、以下を対応します。
・reCAPTCHAにサイトを登録
・HTML上の実装
・PHPを使った検証

# reCAPTCHAにサイトを登録

![reCAPTCHA-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574173/4d92cfb9-31d7-e35d-e2d6-b47057d513e7.png)

### ラベル
これは識別用に管理しやすい名前を入れます


### reCAPTHAタイプ
今回はreCAPTHAタイプをv2を選択
「私はロボットではありません」チェックボックスを選択

### ドメイン
認証を入れたドメインを入れる

### オーナー
オーナーは自分だけであればそのままでOK

### 送信まで
利用条件に同意してアラートにオーナーに送信するかどうかを選び
最後に「送信」を押下

### API キー取得
入力に問題がなければ、APIキー（サイトキーとシークレットキー）が表示されるのでコピーしておきます。APIキーは recaptcha/admin で後から確認することができます。

Site Key　：　reCAPTCHAを表示する際に使用するサイトのキー
Secret Key　：　検証で使用する秘密のキーで公開してはいけません。

これでサイト登録は完了！

# HTML上の実装

![スクリーンショット 2022-08-31 21.25.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574173/f5cba793-d64a-2c51-ef73-88aef212e172.png)

今回はこのように作成しましたという一例です。

### g-recaptchaタグを使って表示

```html
<html lang="ja">
<head>
<title>g-recaptcha タグを使って表示</title>
<script> 
  var verifyCallback = function(response) { //コールバック関数の定義
    //#warning の p 要素のテキストを空に
    document.getElementById("warning").textContent = '';
    //#send の button 要素の disabled 属性を解除
    document.getElementById("send").disabled = false;
  };
  var expiredCallback = function() { //コールバック関数の定義
    //#warning の p 要素のテキストに文字列を設定
    document.getElementById("warning").textContent = '送信するにはチェックを・・・';
    //#send の button 要素に disabled 属性を設定
    document.getElementById("send").disabled = true;
  };
</script>
</head>
<body>
  <h1>g-recaptcha タグを使って表示</h1>
  <form method="post" action="?">
    <div class="g-recaptcha" data-sitekey="サイトキー" data-callback="verifyCallback" data-expired-callback="expiredCallback"></div>
    <p id="warning">送信するにはチェックを入れてください。</p>
    <button id="send" type="submit" disabled>送信</button>
  </form>
  <script src="https://www.google.com/recaptcha/api.js" async defer></script>
</body>
</html>
```

サイトキーのところには先ほど取得した Site Key を入れてください

この記述で見た目上のチェックボックスが出来上がりました。

### g-recaptcha-response（レスポンス）

ユーザがウィジェットにチェックを入れて成功すると、API により以下のようなレスポンス（トークン）が生成されます。

```
03AERD8Xr85M-qcg5EoivhRUI9RgNagFmqwGUKZcXupYI_2tcBLncMtupBlxGiT4C0YYOUI7R4k3o
NX4OCYI9kq83tmTqG1MuNEIexHli-qNd5FLE7XKpOi3Tliy5ZVUFmaeg1qwCnzGUKn1Pd7ae79xn
・・・中略・・・
PEn1Pd7ae9fX_aeg1fNQME9mNNCnzMp8_ATvQ
```

この値を使ってサーバ側で検証を行います。この値は以下の方法で取得することができます。

コールバック関数のパラメータ： function(response) の response
grecaptcha.getResponse メソッド（返り値）
フォームを送信した際に生成される $_POST["g-recaptcha-response"]
このレスポンス（g-recaptcha-response）はトークンとも呼ばれ、有効期間は2分間です。

今回は`フォームを送信した際に生成される $_POST["g-recaptcha-response"]`を使ってPHPで検証します。

# PHPを使った検証
reCAPTCHA を設置しただけでは意味がないので、サーバ側でレスポンスがユーザにより生成されたものかを検証する必要があります。

以下のような流れで判定します。
・ユーザのレスポンス（トークン）を取得（$_POST[ 'g-recaptcha-response' ]）
・API を使ってトークンを検証（API にトークンを送信して検証結果を取得）
・API から取得した値（検証結果）を基に判定

フォーム送信後の完了画面などでPHPで実装しました。


```php
  $recaptcha = $_POST['g-recaptcha-response'];
  if (isset($recaptcha)) {
      $captcha = $recaptcha;
  } else {
      $captcha = '';
  }
  $secretKey = "シークレットキー";
  $url="https://www.google.com/recaptcha/api/siteverify?secret={$secretKey}&response={$captcha}";
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  curl_setopt( $ch, CURLOPT_URL, $url );
  curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
  $result = curl_exec( $ch );
  curl_close($ch);

  $resp_result = json_decode($result,true);
  if(intval($resp_result["success"]) !== 1) {
    // reCAPTCHA承認失敗時の処理
    header('Location: サイトURL');
    exit;
  }
```

シークレットキーのところには先ほど取得した Secret Key を入れてください
サイトURLのところには設定したい失敗時の遷移先をいれてください（エラーメッセージを出すに変えてもいいですね）


file_get_contents() か cURL 関数を使って取得できます。
今回は cURL 関数を使いました。

これで設定完了になります。

# 結果確認

![reCAPTCHA-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574173/58e0f4fe-d932-6cdc-a06d-fc08be1a8925.png)

検証の結果を受け取れています。
目的はスパムメール対策でしたがこれで綺麗に止まったためひとまず安心です。

# 参考
https://www.webdesignleaves.com/pr/plugins/google_recaptcha.php
https://www.hai2mail.jp/column/2020/0509.php