【问题标题】:Google reCAPTCHA: How to get user response and validate in the server side?Google reCAPTCHA:如何在服务器端获取用户响应和验证?
【发布时间】: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 提供的选项?

我有什么想念的吗?

【问题讨论】:

    标签: java javascript recaptcha


    【解决方案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 在这里阅读:stackoverflow.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; 
       }
      }
      

      【讨论】:

      • 如果我理解正确,您只想在客户端验证验证码!让你可以在客户端验证,那么问题是需要验证码吗?在后端验证验证码的原因是,前端可以被愚蠢的机器人操纵或模拟,然后,例如创建用户并向您的应用程序发送垃圾邮件。
      • 在这里尝试服务器站点:stackoverflow.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"))
      猜你喜欢
      • 2015-04-01
      • 2015-02-01
      • 2017-08-09
      • 1970-01-01
      • 2016-01-01
      • 2018-10-28
      • 1970-01-01
      • 2022-06-13
      • 1970-01-01
      相关资源
      最近更新 更多