Google reCAPTCHA v3の続き。
Google reCAPTCHA v2
いわゆる 「ロボットではありません」です。
v3はそれが表示されないのですが、v3が新しくてよい、というわけではなく以下のような区別のようです。
- v2: スパムの判定をGoogleに任せる
- v3: スパムの判定を自分で行い、細かい制御を行う
- ハンドリングしてあとから制御したりできるメリットが有る
key, secretの取得
https://www.google.com/recaptcha/admin/create
ここからkeyとsecretを発行します。
フロントエンド
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<div class="g-recaptcha" data-sitekey="YOUR_KEY"></div>
以下のようなHTMLが生成されます。iframeですね。
<iframe title="reCAPTCHA" src="https://www.google.com/recaptcha/api2/anchor?ar=1&k=xxxxxxxx&co=xxxxxxx.&hl=ja&v=xxxxxxx&size=normal&cb=xxxxxx" width="304" height="78" role="presentation" name="a-xxxxxx" frameborder="0" scrolling="no" sandbox="allow-forms allow-popups allow-same-origin allow-scripts allow-top-navigation allow-modals allow-popups-to-escape-sandbox"></iframe>
バックエンド
g-recaptcha-response
というパラメータが渡されるので、それをバックエンドからGoogleのAPIをリクエストすることで検証します。
今回はAPIのレスポンスを表示しています。
$captcha = $_POST['g-recaptcha-response'];
if (!isset($captcha)) {
echo "g-recaptcha-response is not set";
return;
}
$secret = "YOUR_SECRET";
$verifyResponse = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=".$secret."&response=".$captcha);
echo $verifyResponse;
テストページ
今回、ターゲットになるフォーム
僕の実験サイトなので好きに触ってみてください。
試してみた
正常系
{
"success": true,
"challenge_ts": "2022-02-23T08:36:24Z",
"hostname": "pokosho.com"
}
JSでクリックしてみる
iframeなので操作できません。
これができたら、Twitterをiframeで表示して、ようこそ @kaiba さん! って出せてしまいますからね。
ちなみにCORSのエラーですので、自社サービス間とかは許可することで取得できますね。
Blocked a frame with origin "https://pokosho.com" from accessing a cross-origin frame.
headless chrome(puppeteer)
JSで取得できないので座標で押してみる。
.g-recaptcha
で座標を取得して、チェックボックス内をクリックします。
左端から右、下に30pxをクリックします。
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://pokosho.com/a/recaptcha/v2.html',
{'timeout': 10000, 'waitUntil':'load'}
);
await page.waitForTimeout(1000);
const selector = ".g-recaptcha";
const recaptchaPosition = await page.evaluate((selector) => {
var el = document.querySelector(selector);
var rect = el.getBoundingClientRect();
return {
height: rect.height,
width: rect.width,
x: rect.left,
y: rect.top
};
}, selector);
const margin = 30;
await page.mouse.move(recaptchaPosition.x + margin, recaptchaPosition.y + margin, { steps: 1 });
await page.mouse.click(recaptchaPosition.x + margin, recaptchaPosition.y + margin);
await page.waitForTimeout(1000);
await page.click('#submit');
const json = await page.content();
console.log(json);
await browser.close();
})();
{
"success": true,
"challenge_ts": "2022-02-23T09:05:21Z",
"hostname": "pokosho.com"
}
え… マジで…?
まとめ
- Google reCAPTCHA v2「ロボットではありません」ならマウスの動きとかを見てロボットかどうか判定してくれる。そう考えてた時期が俺にもありました。
- Google reCAPTCHA v2のボタンはiframeなのでJSでは押しづらい。
- Puppeteerで座標を指定してクリックするとスパムにはならなかった。