no-image

Python の CGI で reCAPTCHA v2 を使う

ちょっと前までは人間でも読解困難な文字を読ませていた CAPTCHA ですが、Google の reCAPTCHA v2 では人間である可能性が高い場合は「私はロボットではありません」というチェックを入れるだけとなって、かなりユーザへの負担が軽減されました。

既にクリックすら必要ない reCAPTCHA v3 のベータテストが行われているので、もしかしたらすぐに v3 へ移行してしまうかもしれませんが、現時点ではまだベータ版ということで v2 を選んでいます。

reCAPTCHA v2 を自分のサイトに導入するには、クライアントに表示されるページとサーバの両方にコードの追加が必要となります(実体は両方ともサーバにあるファイルですね)。

流れとしては下記の通りです。

  1. reCAPTHA のページで登録を行う
  2. ユーザに表示する form にコードを埋め込む(JavaScript の読み込みと HTML)
  3. form からの値を Google に投げて判別するコードをサーバ側に追加する

reCAPTCHA の登録

https://www.google.com/recaptcha/ を開き、"My reCAPTCHA" から登録を行います。余談ですが右下に reCAPTCHA のマークが表示されているので、このページ自体も reCAPTCHA で保護されていますね。

reCAPTCHA トップ画面

reCAPTCHA トップ画面

"Register a new site" から新しくサイトを登録します。自分の区別しやすい名前とドメイン名を入力するだけです。

reCAPTCHA register

登録したサイトを開くと設定の仕方が載っているので、これを参考にソースやコードを書き換えます。癖で secret にモザイクかけてしまいましたが、HTML に書かれるから隠す意味はありませんね。

reCAPTCHA secret

クライアントに表示される HTML の変更

2 点だけです。

head 要素に JavaScript の読み込みを追加

<script src='https://www.google.com/recaptcha/api.js'></script>

form 要素に div 要素を追加する

<div class="g-recaptcha" data-sitekey="XXXXXXXXYOURSECRETXXXXXXXXX"></div>

これが reCAPTCHA v2 のチェックボックスになります。

ここまでで次のような表示が現れたら OK です(ID: の入力欄は関係ありません)。

reCAPTCHA form

サーバ側 Python コードの修正

今回は昔ながらの手法で POST された form を読み取る CGI を対象としています。

使うモジュールは次の通り。

import cgi
import urllib, urllib2
import json

cgi は form の値を読み取るために、urllib, urllib2 は Google の API にアクセスするために、json は API の返答を読み取るために使います。

後は通常の form のように 'g-recaptcha-response' の値を取得して、'https://www.google.com/recaptcha/api/siteverify' に対して secret と 'g-recaptcha-response' の値を POST します。

# form から g-recaptcha-response の値を取得
form = cgi.FieldStorage()
response = form.getfirst('g-recaptcha-response', '')

# API で値を検証する
url = 'https://www.google.com/recaptcha/api/siteverify'
secret = 'XXXXXXXXYOURSECRETXXXXXXXXX'
params = urllib.urlencode({'secret': secret, 'response': response})
req = urllib2.Request(url, params)
res = json.loads(urllib2.urlopen(req).read())

# 検証結果
if res['success']:
    # ここに reCAPTCHA 成功時の処理を書く
    print('Passed reCAPTCHA')
else:
    # ここに reCAPTCHA 失敗時の処理を書く
    print('Failed to pass reCAPTCHA')

response は JSON で帰ってきますが、簡単に使うだけなら 'success' の値だけを取得すれば OK です。response の JSON は次のような内容を含んでいます(https://developers.google.com/recaptcha/docs/verify)。

{
  "success": true|false,
  "challenge_ts": timestamp,  // timestamp of the challenge load (ISO format yyyy-MM-dd'T'HH:mm:ssZZ)
  "hostname": string,         // the hostname of the site where the reCAPTCHA was solved
  "error-codes": [...]        // optional
}

これだけなので、bot 対策に悩まされているなら試してみる価値はあります。