こんばんはエンジニアの眠れない夜です。
ボットによるアカウントの作成や不正利用などで困っていませんか?
そんな時はGoogleのreCAPTCHA(リキャプチャ)を使いましょう。
リキャプチャを使うとボットによるアカウントの作成やフォームの送信、サービスの不正利用を簡単に防ぐことができます。
※ 間違っているところなどありましたらご指摘くださいm(_ _)m
reCAPTCHA(リキャプチャ)とは
キャプチャとはいろんなサイトでよく見かけるこういうやつです。
リキャプチャーは3つのバージョンがあります。
リキャプチャVr 1
読みづらい文字や数字を入力するものでした。最近ではディープラーニングの発達により突破されてしまうため現在では廃止されています。
リキャプチャVr 2
クリックするだけのタイプのものと、画像をポチポチ選択するタイプのものです。
認証が厳しく何度も入力を求められるとユーザーはめんどくさくなって離脱してしまいます。
リキャプチャ Ver 3
利用者に負荷をかけないように自動でスコアで判定されるように改良されました。
右下にあるキャプチャのマークが表示されるだけです。
特に理由がなければバージョン3を利用するといいでしょう。
リキャプチャ エンタープライズ版
Google Cloud から利用でき、より細かい設定を行ったり、ディープランニングでパターンを学習させることができます。
リキャプチャの導入方法
まずは、リキャプチャを導入するための全体像を確認しましょう。
やることは大きく分けると3つです
- リキャプチャを利用するサイトのドメインを登録する
- フロントエンドにリキャプチャーを設置する
- バックエンドでリキャプチャから取得されたトークンをもとに結果を取得、判定する
リキャプチャに登録する
こちらのサイトで自分がリキャプチャを導入したいサイトのドメインを登録します。
ドメイン単位の認証なのでサイトごとに登録します。もちろん無料で利用できます。
(月間100万回を超えるとエンタープライズ版を利用する必要があったと思います。)
ドメインにはサブドメインを設定したりポート番号を指定することもできます。
設定を済ませるとサイトキー(パブリックキー)とシークレットキーが取得できます。(後で使います)
また、本番環境とローカル環境で分けるためにローカル用の設定も追加しておくといいでしょう。
ローカル環境でテストするようのドメインには localhost や IP アドレスを指定するといいです。
フロントエンドの実装(JavaScript、HTML)
フォームの中にこのコードを貼り付けます。
<input type="hidden" name="recaptcha_response" id="recaptchaResponse">
続いて、同じページの中に次のコードを貼り付けます。
<script src="https://www.google.com/recaptcha/api.js?render={{ site_key }}"></script>
<script>
$(document).ready(function () {
grecaptcha.ready(function () {
grecaptcha.execute(`{{ site_key }}`, {action: 'submit'}).then(function (token) {
document.getElementById('recaptchaResponse').value = token;
});
});
});
</script>
このコードはページが読み込まれた時に、リキャプチャーを実行します(execute
)。
※ {{ site_key }} は後ほどバックエンドで設定します。
その結果を一つ目に貼り付けたコードに設定します。
document.getElementById('recaptchaResponse').value = token;
フォームを送信した時に、token
が一緒に送信されます。
バックエンドから ’recaptcha_response’ をキーに指定すると、トークンを取得できます。
このトークンは2分以内、且つ一度だけ利用できます。
Django:バックエンドの設定
バックエンドの設定を簡単にするためのクラスを用意しました。
本番環境と開発環境をDEBUGの値でスイッチできます。
secret = ‘YOUR_SECRET_KEY’
site_key = ‘YOUR_SITE_KEY’
self.secret = ‘YOUR_LOCAL_SECRET_KEY’
self.site_key = ‘YOUR_LOCAL_SITE_KEY’
は先程取得した値を貼り付けましょう。
このコードを保存してviews.pyと同じ階層に保存します。
(views.pyに貼り付けても大丈夫ですが、views.pyをコンパクトに収めるためにファイルを分けたほうが良いです。)
バックエンドでリキャプチャの設定でやることは2つあります。
- フォームを設置しているページに サイトキー {{ site_key }}を渡すこと
- フォームからトークンを受け取って結果を取得、判定すること
です。
この先はクラスベースビューを利用している前提で話を進めます。
サイトキー(site_key)を渡す
まずは先ほど貼り付けた Recaptcha()
のインスタンスを作成します。
from myapp.settings import DEBUG
class SignupView(CreateView):
recaptcha = Recaptcha(DEBUG)
DEBUGは setting.py のDEBUGをインポートしてください。(myapp を適宜変更)
フロントエンドで貼り付けたコードの中に {{ site_key }} が使えるようにコンテキストを設定します。
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['site_key'] = self.recaptcha.site_key
return context
フォームから送信された ’recaptcha_response’ を受け取ってリキャプチャの結果を取得、判定します。
def form_valid(self, form):
recaptcha_response = self.request.POST.get('recaptcha_response')
recaptcha_results = self.recaptcha.get_results(recaptcha_response)
if recaptcha_results.get('success') == False and recaptcha_results.get('score') < 0.8:
return HttpResponse('Google Captcha error',status=400)
recaptcha_results
は辞書で次のような結果が返ってきます。
{'action': 'submit',
'challenge_ts': '2021-06-18T15:32:31Z',
'hostname': '127.0.0.1',
'score': 0.9,
'success': True}
successとscore を使って判定をしています。
if recaptcha_results.get('success') == False and recaptcha_results.get('score') < 0.8:
判定の基準を厳しくしたい場合はscoreを0.0 ~ 1.0 の間で調整しましょう。
ここまでの内容でクラスの全体像はこんな感じになります。
class SignupView(CreateView):
model = User
form_class = UserForm
template_name = "base/signup.html"
success_url = reverse_lazy('base:signup_done')
recaptcha = Recaptcha(DEBUG)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['public_key'] = self.recaptcha.public_key
return context
def form_valid(self, form):
recaptcha_response = self.request.POST.get('recaptcha_response')
recaptcha_results = self.recaptcha.get_results(recaptcha_response)
if recaptcha_results.get('success') != True:
return HttpResponse('Google Captcha error',status=400)
キャプチャの JavaScript が読み込めずにエラーが出た場合
Error: Invalid site key or not loaded in api.js
というエラーが出たり、
というエラーが出ることがあります。
こういうときは登録しているドメインやIPアドレスがあっているかを確認しましょう。
登録したドメインと一致しているのにこういったエラーが出るときは、時間を置いてもう一度試してみましょう。
コメントを残す