思うところがあってreCAPTCHA v3を触ってみたく、試してみました。
バックエンドの環境準備も面倒だったので、バックエンドはGASでやってみました。
JavaScriptとHTMLしかサンプルに登場しないのも良し。
Google reCAPTCHA v3
いわゆる 「ロボットではありません」
なんですが、それはv2まで。
v3はそれが要らなくなったらしい。
今回、ターゲットになるフォーム
僕の実験サイトなので好きに触ってみてください。
よくあるお問い合わせフォームになります。
form名もcontactで悪いbotさんに拾ってもらえそう?
key, secretの発行
https://www.google.com/recaptcha/admin/create
ここからkeyとsecretを発行します。
keyはフロントエンドに埋め込むので誰に見られても良いものですがsecretはその名の通り秘密にすべきもので、バックエンドで使います。
フロントエンド
Googleにkeyを渡し、tokenを受け取り、バックエンドにわたす必要があります。
<input type="hidden" name="recaptcha" id="recaptcha" />
hiddenパラメータを用意しました。
<script src="https://www.google.com/recaptcha/api.js?render=[key]"></script>
recaptchaのスクリプトにkeyを渡して読み込みます。
[key]
には取得したkeyを入れてくださいね。
grecaptcha.ready(function() {
grecaptcha.execute('[key]', {action: 'homepage'}).then(function(token) {
var recaptcha = document.getElementById('recaptcha');
recaptcha.value = token;
});
});
[key]
には取得したkeyを入れてくださいね。
grecaptcha.execute
を呼ぶとtokenが得られますので、上記のhiddenパラメータに入力しておきます。
actionはformのactionではなく、Googleの指定するactionで、 homepage
, login
, social
, e-commerce
のいずれかを指定します。
名前からある程度わかりますが、詳しくはドキュメントを参照ください。
バックエンド(GAS)
雑にもほどがありますが、受け取ったパラメータをspreadsheetにぶちこみます。
function doPost(e) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var values = [];
// TODO: パラメータの順番が保証されているとは限らないのでこんなことをしてはいけません
for (key in e.parameters) {
values.push(e.parameters[key][0]);
}
var recaptchaRes = validateRequest(e);
// TODO: 本当はここで recaptchaRes.success ではないものを捨てる
// 今回は全部みたいので乱暴にspreadsheetに入れています。
values.push(recaptchaRes);
sheet.appendRow(values);
}
function validateRequest(e) {
var payload = {
"secret": "[secret]",
"response": e.parameters["recaptcha"][0],
};
var options = {
"method" : "post",
"payload" : payload
};
var res = UrlFetchApp.fetch("https://www.google.com/recaptcha/api/siteverify", options);
return res;
}
[secret]
はsecretをいれてください。外部にもれないように注意しましょう。
試してみた
正常系
{
"success": true,
"challenge_ts": "2019-08-16T14:21:18Z",
"hostname": "pokosho.com",
"score": 0.9,
"action": "homepage"
}
高いスコアです。
JSでクリックしてみる
Chrome Developer Toolを立ち上げ、consoleからJSでクリックしてみる。
document.getElementById("submit").click();
{
"success": true,
"challenge_ts": "2019-08-16T14:21:40Z",
"hostname": "pokosho.com",
"score": 0.9,
"action": "homepage"
}
なんだと?
v2の「私はロボットではありません」に対してこれをやると怒られたのですが…!
ブックマークレットとかも使えそうですね。
同じリクエストを飛ばしてみる
Chrome Developer ToolからCopy as cURLする。
{
"success": false,
"error-codes": [
"timeout-or-duplicate"
]
}
おお〜。
headless chrome
環境構築が面倒なので…。誰か編集リクエストください…。
まとめ
- 「私はロボットではありません」の印象が強すぎて「UXを損ねるのでは?」という懸念が挙がるがそんなことはない!
- JS読み込んで終わり、というわけにはいかない。botかどうかの判定はバックエンドで行う。
- Googleからドメインを指定してkeyとsecretを発行する。
- keyはフロントエンドからGoogleに渡す。するとtokenが得られる。
- tokenをバックエンドに渡す。
- バックエンドはtokenとsecretをGoogleに渡す。すると判定結果が得られる。
- 判定結果はbool値の
success
のパラメータ見れば良い。 - ReactやVueでやる場合、ライブラリを使うのが良さそうですね。
- 登場人物は多い。駆け出しエンジニアには難しいかも知れない。