Google reCAPTCHA:如何在服务器端获取用户响应和验证?

Posted

技术标签:

【中文标题】Google reCAPTCHA:如何在服务器端获取用户响应和验证?【英文标题】:Google reCAPTCHA: How to get user response and validate in the server side? 【发布时间】:2015-02-02 12:17:30 【问题描述】:

我正在做一个 Java (JSP + Servlet) Web 应用程序(我知道这个问题与技术无关)。我希望使用最新的 Google reCAPTCHA 服务。

我正在使用此处找到的 Google reCAPTCHA 示例:

https://developers.google.com/recaptcha/docs/display#config

<html>
  <head>
    <title>reCAPTCHA demo: Simple page</title>
     <script src="https://www.google.com/recaptcha/api.js" async defer></script>
  </head>
  <body>
    <form action="?" method="POST">
      <div class="g-recaptcha" data-sitekey="my_site_key"></div>
      <br/>
      <input type="submit" value="Submit">
    </form>
  </body>
</html>

我可以看到显示的recaptcha图像如下:

当我检查“我不是机器人”时,我得到以下信息:

如您所见,有一个“验证”按钮,根据我的测试,用户响应会发送给 Google 进行验证。

如何获取用户响应,以便在我自己的后端代码中验证用户响应(如 Google 在https://developers.google.com/recaptcha/docs/verify 建议的那样)。

g-recaptcha-response POST parameter when the user submits the form on your site

在服务器端,我可以通过单击“提交”按钮,仅在用户首先通过 Google 成功验证时从参数“g-recaptcha-response”获取用户输入。否则,“g-recaptcha-response”在服务器端为空白。这意味着我只有在客户端验证成功后才能进行服务器端验证。如果是这样,在服务器端进行另一次验证有什么意义,这是 Google reCAPTHA 提供的选项?

我有什么想念的吗?

【问题讨论】:

【参考方案1】:

新的 Google Recaptcha 最酷的地方在于验证现在完全封装在小部件中。这意味着,小部件将负责提出问题,一直验证响应,直到确定用户实际上是人类,然后您才会获得 g-recaptcha-response 值。 p>

但这并不能保证您的网站免受 HTTP 客户端请求伪造的影响。

任何具有 HTTP POST 知识的人都可以将随机数据放入 g-recaptcha-response 表单字段中,并关注您的网站,使其认为该字段是由 google 小部件提供的。所以你必须验证这个令牌。

在人类语言中会是这样的,

你的服务器:嘿 Google,有个家伙告诉我他不是机器人。他说你已经证实他是人类,他让我给你这个令牌作为证明。 Google:嗯...让我检查一下这个令牌...是的,我记得这个家伙我给了他这个令牌...是的,他是由骨肉制成的,让他通过。 你的服务器:嘿 Google,还有一个家伙告诉我他是人类。他还给了我一个令牌。 Google:嗯……这和你上次给我的令牌一样……我很确定这家伙是想骗你。告诉他离开你的网站。

验证响应非常简单。只需发出 GET 请求即可

https://www.google.com/recaptcha/api/siteverify?secret=your_secret&response=response_string&remoteip=user_ip_address

并将 response_string 替换为您之前通过 g-recaptcha-response 字段获得的值。

您将获得带有 success 字段的 JSON 响应。

更多信息在这里: https://developers.google.com/recaptcha/docs/verify

编辑:根据documentation here,它实际上是一个 POST。

【讨论】:

TheRueger,非常感谢您的意见!在发表这篇文章之前,我阅读了你在这里提到的所有内容。 Google reCAPTCHA 表明服务器端验证是验证方法之一。我对吗? “您只需要询问谷歌 g-recaptcha-response 是否有效。”是什么意思。我对“验证由谷歌小部件自动完成”和“您将获得带有成功字段的 JSON 响应”这两个步骤感到困惑。如果第一步成功,为什么要第二步?问候 嘿@curious1,需要第二步的原因很简单。来自浏览器的所有输入都可能是伪造的。我的意思是您不能仅在客户端验证用户输入,因此谷歌正在验证用户是否为人类,但他不能只向您发送一个名为“UserIsHuman”真/假的隐藏字段。那很容易被伪造。所以谷歌正在验证用户并将结果存储在一个 id 下,这允许您询问谷歌该 id 是否是一个人或不在您的后端。另见link 如果您向.../siteverify 发出GET 请求,您是在将私钥 放入查询字符串中吗?那怎么能被认为是私钥呢? @yuck 在这里阅读:***.com/questions/323200/… @TheRueger 对https://www.google.com/recaptcha/api/siteverify 的请求不应该是GET 请求,而是POST 请求。见https://developers.google.com/recaptcha/docs/verify。【参考方案2】:

这是了解客户端和服务器端流程的完整演示代码。您可以复制粘贴它并替换 google 站点密钥google 密钥。

<?php 
if(!empty($_REQUEST))

      //  echo '<pre>'; print_r($_REQUEST); die('END');
        $post = [
            'secret' => 'Your Secret key',
            'response' => $_REQUEST['g-recaptcha-response'],
        ];
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL,"https://www.google.com/recaptcha/api/siteverify");
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        $server_output = curl_exec($ch);

        curl_close ($ch);
        echo '<pre>'; print_r($server_output); die('ss');

?>
<html>
  <head>
    <title>reCAPTCHA demo: Explicit render for multiple widgets</title>
    <script type="text/javascript">
      var site_key = 'Your Site key';
      var verifyCallback = function(response) 
        alert(response);
      ;
      var widgetId1;
      var widgetId2;
      var onloadCallback = function() 
        // Renders the HTML element with id 'example1' as a reCAPTCHA widget.
        // The id of the reCAPTCHA widget is assigned to 'widgetId1'.
        widgetId1 = grecaptcha.render('example1', 
          'sitekey' : site_key,
          'theme' : 'light'
        );
        widgetId2 = grecaptcha.render(document.getElementById('example2'), 
          'sitekey' : site_key
        );
        grecaptcha.render('example3', 
          'sitekey' : site_key,
          'callback' : verifyCallback,
          'theme' : 'dark'
        );
      ;
    </script>
  </head>
  <body>
    <!-- The g-recaptcha-response string displays in an alert message upon submit. -->
    <form action="javascript:alert(grecaptcha.getResponse(widgetId1));">
      <div id="example1"></div>
      <br>
      <input type="submit" value="getResponse">
    </form>
    <br>
    <!-- Resets reCAPTCHA widgetId2 upon submit. -->
    <form action="javascript:grecaptcha.reset(widgetId2);">
      <div id="example2"></div>
      <br>
      <input type="submit" value="reset">
    </form>
    <br>
    <!-- POSTs back to the page's URL upon submit with a g-recaptcha-response POST parameter. -->
    <form action="?" method="POST">
      <div id="example3"></div>
      <br>
      <input type="submit" value="Submit">
    </form>
    <script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit"
        async defer>
    </script>
  </body>
</html>

【讨论】:

【参考方案3】:

您好好奇,您也可以在客户端验证您的 google recaptcha100% 工作让我验证您的 google recaptcha,请参见下面的代码 这段代码在 html 正文中:

 <div class="g-recaptcha" id="rcaptcha" style="margin-left: 90px;" data-sitekey="my_key"></div>
 <span id="captcha" style="margin-left:100px;color:red" />

这段代码放在调用get_action(this)方法表单按钮的头部:

function get_action(form) 

var v = grecaptcha.getResponse();
if(v.length == 0)

    document.getElementById('captcha').innerHTML="You can't leave Captcha Code empty";
    return false;

 if(v.length != 0)
 
    document.getElementById('captcha').innerHTML="Captcha completed";
    return true; 
 

【讨论】:

如果我理解正确,您只想在客户端验证验证码!让你可以在客户端验证,那么问题是需要验证码吗?在后端验证验证码的原因是,前端可以被愚蠢的机器人操纵或模拟,然后,例如创建用户并向您的应用程序发送垃圾邮件。 在这里尝试服务器站点:***.com/questions/31354633/… @TheRueger 不就是这样吗?我不明白它是如何工作的,如果我错了,请纠正我,您在后端验证令牌,然后再次将其返回到客户端,在那里您将检查表单是否可以提交。最后的检查也可以被操纵,对吗?机器人可以在发送表单之前摆脱最后一次检查,还是我错了? @OmarRuder 前端应该只首先检查验证码的响应以通知用户。但验证码验证的响应必须包含在提交的表单中。然后后端必须再次询问谷歌从前端收到的验证码是否正确。只有这样后端才能完全接受表单。【参考方案4】:

我在登录 servlet 中使用的一种方法来验证 reCaptcha 响应。使用 java.json 包中的类。在 JsonObject 中返回 API 响应。

检查成功字段的真假

private JsonObject validateCaptcha(String secret, String response, String remoteip)

    JsonObject jsonObject = null;
    URLConnection connection = null;
    InputStream is = null;
    String charset = java.nio.charset.StandardCharsets.UTF_8.name();

    String url = "https://www.google.com/recaptcha/api/siteverify";
    try             
        String query = String.format("secret=%s&response=%s&remoteip=%s", 
        URLEncoder.encode(secret, charset), 
        URLEncoder.encode(response, charset),
        URLEncoder.encode(remoteip, charset));

        connection = new URL(url + "?" + query).openConnection();
        is = connection.getInputStream();
        JsonReader rdr = Json.createReader(is);
        jsonObject = rdr.readObject();

     catch (IOException ex) 
        Logger.getLogger(Login.class.getName()).log(Level.SEVERE, null, ex);
    
    finally 
        if (is != null) 
            try 
                is.close();
             catch (IOException e) 
            

        
    
    return jsonObject;

【讨论】:

我不断收到此错误:java.lang.ClassCastException: javax.json.JsonValue$2 每次我尝试从返回值解析“成功”时都无法转换为 javax.json.JsonString, json对象。这是引发错误的实际调用,有什么想法吗? JsonString 响应 = jsonObject.getJsonString("success"); 这个命令也失败了:String response = jsonObject.getJsonString("success");我最终这样做了: String returnValue = jsonObject.getOrDefault("success", null).toString();对此不满意,丑陋和不雅。花了 3 个小时为此发疯。 尝试布尔成功 = jsonObject.getBoolean("success"))

以上是关于Google reCAPTCHA:如何在服务器端获取用户响应和验证?的主要内容,如果未能解决你的问题,请参考以下文章

如何解决 Google v3 reCaptcha 超时?

google recaptcha使用

如何将 Google Recaptcha v2 实施到限制访问 Google Recaptcha 的 Web 应用程序

如何在 vuetify 上添加 google recaptcha 3?

如何在客户端验证 google recaptcha?

如何隐藏 Google Invisible reCAPTCHA 徽章