如何解决 Google v3 reCaptcha 超时?

Posted

技术标签:

【中文标题】如何解决 Google v3 reCaptcha 超时?【英文标题】:How to solve Google v3 reCaptcha timeout? 【发布时间】:2019-08-10 14:52:57 【问题描述】:

我们有一个 php 表单,它在 reCaptcha 上有多个选项卡和超时。一切都在一个页面中完成,如果表单在

一个解决方案的想法是将表单处理和reCaptcha移动到辅助页面进行处理。

问题在于表单页面轮询谷歌服务以获取 reCaptcha 并收集令牌值到隐藏字段。

<input type="hidden" name="recaptcha_response" id="recaptchaResponse">

问题是如何在服务端处理页面请求这个token?这是客户端表单页面上使用的代码。我需要以某种方式重新生成令牌值以应用为:

$recaptcha_response

这是表单页面上的工作版本。从表单页面删除对发布令牌的要求很容易,只是不确定如何重新生成令牌以在服务器端页面上使用。

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['recaptcha_response'])) 

// Build POST request:
$recaptcha_url = 'https://www.google.com/recaptcha/api/siteverify';
$recaptcha_secret = RECAPTCHA_SECRET_KEY;
$recaptcha_response = $_POST['recaptcha_response'];
$remoteip = $_SERVER['REMOTE_ADDR'];

// Make and decode POST request:
$recaptcha = file_get_contents($recaptcha_url . '?secret=' . $recaptcha_secret . '&response=' . $recaptcha_response. '&remoteip='.$remoteip);
$recaptcha = json_decode($recaptcha);

// Take action based on the score returned:
if ($recaptcha->score >= 0.5) 

编辑添加: 是否会初始化 reCaptcha,直到提交延迟时间问题,因为这似乎是一个选项:

https://developers.google.com/recaptcha/docs/v3

“2. 在某个操作或页面加载时调用 grecaptcha.execute”

【问题讨论】:

您的服务器端看起来还可以,等等 ..,但客户端需要再次执行 grecaptcha.ready(function() grecaptcha.execute( ... ); ) 您说解决方案是不移动到辅助页面(如果 这取决于您何时需要验证码信息,如果您需要它并且它已过期 - 那么再次获取它的唯一方法是让客户端(浏览器)请求一个令牌 - 并且服务器验证它。就个人而言,一旦我验证了客户 - 我不需要重新验证它 - 即使在 10 分钟之后。 因此,与其在提交时检查客户端的页面加载,然后消除超时的可能性。这是另一个概念,它很有意义! 【参考方案1】:

如果您不希望过多更改代码,则另一种方法是将 reCaptcha javascript 包装在命名函数中,设置间隔并轮询该函数,提示 reCaptcha 将新令牌添加到表单元素 10每两分钟令牌到期前的秒数:

function getReCaptcha()
    grecaptcha.ready(function() 
       ...
     );
 

 getReCaptcha();  // This is the initial call
 setInterval(function()getReCaptcha();, 110000);

【讨论】:

这应该被标记为这个问题的正确答案,尽管我将 setInterval 设置为 90*1000 毫秒,因为 Google 文档指出令牌的超时时间是 120 秒。 好答案。虽然,您的示例显示 2.5 分钟而不是 3 分钟。 感谢 cmets 关于 reCaptha 令牌的生命周期。我接受了 OP 的话,生命是 3 分钟,而谷歌的文档说令牌只有 2 分钟的生命。我已经更新了我的答案,以每 110 秒而不是每 150 秒获取一个新令牌。【参考方案2】:

当您使用grecaptcha.execute() 时,它不能解决问题。因为 execute() 也可以抛出错误。要解决此问题,您应该将 execute 放在 try-catch 块中。例如:

grecaptcha.ready(function() 
    try 
      grecaptcha.execute('RECAPTCHA_SITE_KEY', action: 'submit')
        .then(function(token) 
            submitYourForm(token);
        )
     catch (error) 
        yourRetryBlockHere();
    
);

【讨论】:

【参考方案3】:

忽略这里的一切。原因:

    如果你只是在页面加载时生成令牌,它会在 2 分钟后超时,这意味着用户不会对此感到高兴 刷新令牌需要付费(有免费套餐,但使用 X 请求后会付费)

解决方案: 在提交表单时生成令牌! https://jsfiddle.net/skobaljic/rL6fux5w/2/

var webQueryForm = $('#webQuery');
webQueryForm.submit(function(event) 
  e.preventDefault();
  grecaptcha.execute('MYSITEKEY(PUBLIC)', 
     action: 'contact'
     ).then(function(token) 
     $('#recaptchaToken').val(token);
    webQueryForm.submit();
  );
);

【讨论】:

【参考方案4】:

加载 reCaptcha API js 和 Jquery(如果你使用 jquery 代码):

<script src="https://www.google.com/recaptcha/api.js?render=SITE_KEY"></script>
<script  src="https://code.jquery.com/jquery-3.4.1.min.js"></script>

reCaptcha 渲染 Javascript:

  <script type="text/javascript">
     $(document).ready(function()
        setInterval(function()
        grecaptcha.ready(function() 
            grecaptcha.execute('SITE_KEY', action: 'home').then(function(token) 
                $('#recaptchaResponse').val(token);
            );
        );
        , 3000); //you can set timeout for expired.
     );
     
  </script>

网站验证:

<?php 
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['submit'])) 
        if(isset($_POST['recaptcha_response']) && !empty($_POST['recaptcha_response']))
            $recaptcha_url = 'https://www.google.com/recaptcha/api/siteverify';
            $recaptcha_secret = 'SECRET_KEY';
            $recaptcha_response = $_POST['recaptcha_response'];
            $response = file_get_contents($recaptcha_url . '?secret=' . $recaptcha_secret . '&response=' . $recaptcha_response);
            $recaptcha = json_decode($response);
            if ($recaptcha->success == true && $recaptcha->score >= 0.5) 
                echo $response;
                echo '<br>Form Submitted Successfully';
             else  
                echo $response;
                echo '<br>reCaptcha varification failed';
            
        else 
            echo 'reCaptcha is empty';
         
    
?>

html 表单:

<form method="POST">
    <label class="label">Name</label>
    <input type="text" name="name" class="input" placeholder="Name" required>
    <button type="submit" name="submit" class="button is-link">Send Message</button>
    <input type="hidden" name="recaptcha_response" id="recaptchaResponse">
</form>

【讨论】:

【参考方案5】:

我们最近也遇到了这个问题。我在 GitHub 上找到了这个解决方案,它对我们来说效果很好。

这样做的好处是仅在用户与页面交互(例如提交表单)时才请求令牌,而不必一直请求令牌。

<script>
  grecaptcha.ready(function() 
      document.getElementById('contactform').addEventListener("submit", function(event) 

        event.preventDefault();

        grecaptcha.execute('mykey', action: 'homepage').then(function(token) 
           document.getElementById("googletoken").value = token; 
           document.getElementById('contactform').submit();
        );        
      , false);

  );
</script>

【讨论】:

谢谢,下次我们编写类似的代码时,我会试试你的方法。 刚刚遇到了同样的问题,并使用命名函数实现了该方法并侦听“提交”,并且效果很好。 rifton007 于 2 月 13 日发表评论 @iwasherefirst2 解决方案并不完美。因为,当我们在发送之前请求令牌时。表单需要等待几秒钟才能接收令牌并与数据一起发送。 是的,所以在这种情况下,您可以在event.preventDefault(); 之后显示某种“工作”指示符,这样用户就知道正在提交表单,这应该解决大多数问题。 【参考方案6】:
<script type="text/javascript">
function grecaptcha_execute()
    grecaptcha.execute('RECAPTCHA_SITE_KEY', action: 'homepage').then(function(token) 
        document.getElementById('recaptchaResponse').value=token;
    );

grecaptcha.ready(function() 
    grecaptcha_execute();
);
</script>

<?php
if ($recaptcha->success) 
    echo '<p style="color: #0a860a;">CAPTCHA was completed successfully!</p>';
else
    $error_codes = 'error-codes';
    if (isset($Retorno->$error_codes) && in_array("timeout-or-duplicate", $Retorno->$error_codes)) 
        $captcha_msg = "The verification expired due to timeout, please try again.";
    ?>
    <script>grecaptcha_execute();</script>
    <?php
     else 
        $captcha_msg = "Check to make sure your keys match the registered domain and are in the correct locations.<br> You may also want to doublecheck your code for typos or syntax errors.";
    
    echo '<p style="color: #f80808;">reCAPTCHA error: ' . $captcha_msg . '</p>';

?>

【讨论】:

以上是关于如何解决 Google v3 reCaptcha 超时?的主要内容,如果未能解决你的问题,请参考以下文章

Google 的 reCAPTCHA v3 的工作原理

Google reCaptcha v3 与 google reCaptcha Enterprise

reCAPTCHA v3 - 错误:没有reCAPTCHA客户端

使用 ng-recaptcha 将 Google reCaptcha v3 集成到 Angular 应用程序中

Google Recaptcha v3 示例演示

带有 Google Recaptcha v3 的 Django 联系表