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 Recaptcha v2 实施到限制访问 Google Recaptcha 的 Web 应用程序