0
Help us understand the problem. What are the problem?

posted at

updated at

Google reCAPTCHA v2はどうするとスパム判定されるのか?

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&amp;k=xxxxxxxx&amp;co=xxxxxxx.&amp;hl=ja&amp;v=xxxxxxx&amp;size=normal&amp;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で座標を指定してクリックするとスパムにはならなかった。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
0
Help us understand the problem. What are the problem?