php - 如何验证 Google Recaptcha V3 响应?

标签 php recaptcha invisible-recaptcha

如何在客户端和服务器端 (php) 集成 Google reCAPTCHA Version 3。以下代码用于显示 recaptcha,但效果不佳。如何进行此集成。

<html>

<head>
  <script src='https://www.google.com/recaptcha/api.js?render=XXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'></script>
</head>

<body>
  <script>
    grecaptcha.ready(function() {
      grecaptcha.execute('XXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', {
        action: 'action_name'
      });
    });
  </script>

  <form action="verify.php" method="post">
    <input type="text" name="name" placeholder="Your name" required>
    <input type="email" name="email" placeholder="Your email address" required>
    <textarea name="message" placeholder="Type your message here...." required></textarea>

    <input type="submit" name="submit" value="SUBMIT">

  </form>

</body>

</html>

验证.php

<?php

    if(isset($_POST['g-recaptcha-response']) && !empty($_POST['g-recaptcha-response'])) {
        //your site secret key
        $secret = 'XXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
        //get verify response data
        $verifyResponse = file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret='.$secret.'&response='.$_POST['g-recaptcha-response']);
        $responseData = json_decode($verifyResponse);
        if($responseData->success):

             print_r("Working Fine"); exit;
        else:
             print_r("No valid Key"); exit;
        endif;
    } else {
        print_r("Not Working Captcha"); exit;
    }

?>

最佳答案

由 Google reCAPTCHA v3 使用纯 JavaScript 和 PHP 验证的联系表单的简单示例

tldr;跳到底部的代码。

相关 reCAPTCHA 文档等:

(如果 Google 正在倾听,我们喜欢您的工作,如果有一些更详细的示例链接到上述页面,那将是很棒的。)

概述:

  1. 从 Google 获取 key
  2. 在html头部加载recaptcha/api.js
  3. 使用 JavaScript 劫持表单提交,然后从 Google 获取 token
  4. 将带有 token 的表单提交到您的服务器
  5. 从您网站的后端向 Google 发出请求以验证 表单提交
  6. 解释响应并根据需要进行处理

重要提示:“成功”响应参数仅表示验证码评估是否成功,并不表示提交是否可能是垃圾邮件。

“分数”参数是您需要了解的结果。分数越高(介于 0 和 1 之间的数字)提交的内容越有可能是真实的,接受什么阈值(例如 0.5)取决于您。

详细说明:

将以下行添加到 HTML 的头部以加载 recaptcha api.js 代码:

<script src="https://www.google.com/recaptcha/api.js?render=$reCAPTCHA_site_key"></script>

(其中 $reCAPTCHA_site_key 是您的公共(public)“站点 key ”,我已将其保存在“config.php”文件中。)

您需要向您的服务器提交一个 token (从 Google 接收并且对每次提交的表单都是唯一的)。我认为通过 POST 将其与其余表单数据一起发送是最简单的。为此,我在表单中包含一个隐藏字段,如下所示:

<form id="contactForm" method="post" action="contact">
    <!-- other form inputs -->
    <input type="hidden" id="gRecaptchaResponse" name="gRecaptchaResponse">
    <input type="submit" name="contact_submit" value="Send message">
</form>

(注意,“contact”是 contact.php,但我已经用 .htaccess“重写”了 url)

现在我们需要劫持默认表单提交来生成 token 。我们可以在页面加载时生成 token ,但由于 token 仅在两分钟内有效(如果我正在正确阅读 https://developers.google.com/recaptcha/docs/verify 页面)我认为最好在需要将其发送到您网站的服务器时获取它.

为此,我在结束表单标记之后添加了以下内容:

<script>
    contactForm.addEventListener('submit', event => {
        event.preventDefault()
        validate(contactForm)
    });
</script>

我将 validate(form) 函数放在了结束 body 标签之前:

function validate(form) {
    //perform optional error checking on form. If no errors then request a token and put it into the hidden field
    getRecaptchaToken(form)
}

//some other (optional) form validation functions

function getRecaptchaToken(form) {
    grecaptcha.ready(function() {
        grecaptcha.execute($reCAPTCHA_site_key, {action: 'contactForm'}).then(function(token) {
            gRecaptchaResponse.value = token //set the value of the hidden field
            form.submit() //submit the form
        });
    });
}

注意事项:

  • $reCAPTCHA_site_key 是您的公共(public)站点 key
  • action: 'contactForm' 标识此特定的提交 在 Google reCAPTCHA 仪表板中形成表单,并在后端确认它符合预期是一个额外的推荐 安全步骤

在主 PHP 文件中,当收到表单提交时:

//get the IP address of the origin of the submission
$ip = $_SERVER['REMOTE_ADDR'];

//construct the url to send your private Secret Key, token and (optionally) IP address of the form submitter to Google to get a spam rating for the submission (I've saved '$reCAPTCHA_secret_key' in config.php)
$url =  'https://www.google.com/recaptcha/api/siteverify?secret=' . urlencode($reCAPTCHA_secret_key) . '&response=' . urlencode($g_recaptcha_response) . '&remoteip=' . urlencode($ip);

//save the response, e.g. print_r($response) prints { "success": true, "challenge_ts": "2019-07-24T11:19:07Z", "hostname": "your-website-domain.co.uk", "score": 0.9, "action": "contactForm" }
$response = file_get_contents($url);

//decode the response, e.g. print_r($responseKeys) prints Array ( [success] => 1 [challenge_ts] => 2019-07-24T11:19:07Z [hostname] => your-website-domain.co.uk [score] => 0.9 [action] => contactForm )
$responseKeys = json_decode($response, true);

//check if the test was done OK, if the action name is correct and if the score is above your chosen threshold (again, I've saved '$g_recaptcha_allowable_score' in config.php)
if ($responseKeys["success"] && $responseKeys["action"] == 'contactForm') {
    if ($responseKeys["score"] >= $g_recaptcha_allowable_score) {
        //send email with contact form submission data to site owner/ submit to database/ etc
        //redirect to confirmation page or whatever you need to do
    } elseif ($responseKeys["score"] < $g_recaptcha_allowable_score) {
        //failed spam test. Offer the visitor the option to try again or use an alternative method of contact.
    }
} elseif($responseKeys["error-codes"]) { //optional
    //handle errors. See notes below for possible error codes
    //personally I'm probably going to handle errors in much the same way by sending myself a the error code for debugging and offering the visitor the option to try again or use an alternative method of contact
} else {
    //unkown screw up. Again, offer the visitor the option to try again or use an alternative method of contact.
}

注意事项:

  • 这是 Google 响应中的数据 (作为 JSON 对象返回):


   {
     "success": true|false,      // whether this request was a valid reCAPTCHA token for your site
     "score": number             // the score for this request (0.0 - 1.0)
     "action": string            // the action name for this request (important to verify)
     "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
   }

  • 这些是可能的错误代码:
    • missing-input-secret: secret 参数丢失。
    • invalid-input-secret:secret 参数无效或格式错误。
    • 缺少输入响应:缺少响应参数。
    • invalid-input-response:响应参数无效或格式错误。
    • 错误请求:请求无效或格式错误。
    • timeout-or-duplicate:响应不再有效;要么太 旧的或以前使用过。

综合起来:

contact.php

<?php  //contact.php

    require_once('config.php');

    //do server-side validation of other form fields

    if (/*form has been submitted and has passed server-side validation of the other form fields*/) {
        $ip = $_SERVER['REMOTE_ADDR'];
        $url =  'https://www.google.com/recaptcha/api/siteverify?secret=' . urlencode($reCAPTCHA_secret_key) . '&response=' . urlencode($g_recaptcha_response) . '&remoteip=' . urlencode($ip);
        $response = file_get_contents($url);
        $responseKeys = json_decode($response, true);

        if ($responseKeys["success"] && $responseKeys["action"] == 'contactForm') {
            if ($responseKeys["score"] >= $g_recaptcha_allowable_score) {
                //send email with contact form submission data to site owner/ submit to database/ etc
                //redirect to confirmation page or whatever you need to do
            } elseif ($responseKeys["score"] < $g_recaptcha_allowable_score) {
                //failed spam test. Offer the visitor the option to try again or use an alternative method of contact.
            }
        } elseif($responseKeys["error-codes"]) { //optional
            //handle errors. See notes below for possible error codes
            //(I handle errors by sending myself an email with the error code for debugging and offering the visitor the option to try again or use an alternative method of contact)
        } else {
            //unkown screw up. Again, offer the visitor the option to try again or use an alternative method of contact.
        }

        exit;

    } else { //(re)display the page with the form

        echo <<<_END

            <!DOCTYPE html>
            <html lang="en">
                <head>
                    <title>Contact | Your website</title>
                    <link rel="stylesheet" href="css/style.css">
                    <script src="https://www.google.com/recaptcha/api.js?render=$reCAPTCHA_site_key"></script>
                </head>
                <body>

                    <!-- header etc -->

                    <form id="contactForm" method="post" action="contact">
                        //other form inputs
                        <input type="hidden" id="gRecaptchaResponse" name="gRecaptchaResponse">
                        <input type="submit" name="contact_submit" value="Send message">
                    </form>
                    <script>
                        contactForm.addEventListener('submit', event => {
                            event.preventDefault()
                            validate(contactForm)
                        });
                    </script>

                    <!-- footer etc -->

                    <script>
                        function validate(form) {
                            //perform optional client-side error checking of the form. If no errors are found then request a token and put it into the hidden field. Finally submit the form.
                            getRecaptchaToken(form)
                        }

                        //some (optional) form field validation functions

                        function getRecaptchaToken(form) {
                            grecaptcha.ready(function() {
                                grecaptcha.execute($reCAPTCHA_site_key, {action: 'contactForm'}).then(function(token) {
                                    gRecaptchaResponse.value = token
                                    form.submit()
                                });
                            });
                        }
                    </script>
                </body>
            </html>

_END;

config.php

<?php //config.php

//other site settings

// Google reCAPTCHA v3 keys
// For reducing spam contact form submissions

// Site key (public)
$reCAPTCHA_site_key = 'N0t-a-real-0N3_JHbnbUJ-BLAHBLAH_Blahblah';

// Secret key
$reCAPTCHA_secret_key = 'N0t-a-real-0N3_i77tyYGH7Ty6UfG-blah';

// Min score returned from reCAPTCHA to allow form submission
$g_recaptcha_allowable_score = 0.5; //Number between 0 and 1. You choose this. Setting a number closer to 0 will let through more spam, closer to 1 and you may start to block valid submissions.

关于php - 如何验证 Google Recaptcha V3 响应?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50405977/

相关文章:

javascript - 单击单选按钮时,显示/隐藏具有动态变化的 ID 或类的 div

php - 使用 SWIG 将 C++ 类集成到 PHP 中

java - Linux 服务器上的 Recaptcha 连接超时

google-analytics - 谷歌 reCAPTCHA V2 分析

javascript - 不可见的 reCAPTCHA - 缺少必需的参数 : sitekey

javascript - reCAPTCHA 不可见,无需回调函数

php - 如何在 PHP 中检查 IPv6 地址是否在特定网络中(用于 ACL 实现)

php - 使用 laravel php-mysql 在一段时间内仅更改一次字段值

c# - 如何在 c# Selenium 中查找 reCAPTCHA 元素并单击它

javascript - 请求的资源上不存在 'Access-Control-Allow-Origin' header 。响应的 HTTP 状态代码为 405