如何在服务器端验证 Google reCAPTCHA v3?
Posted
技术标签:
【中文标题】如何在服务器端验证 Google reCAPTCHA v3?【英文标题】:How to validate Google reCAPTCHA v3 on server side? 【发布时间】:2015-02-01 03:50:09 【问题描述】:我刚刚使用复选框设置了新的 google recaptcha,它在前端工作正常,但是我不知道如何使用 php 在服务器端处理它。我尝试使用下面的旧代码,但即使验证码无效,也会发送表单。
require_once('recaptchalib.php');
$privatekey = "my key";
$resp = recaptcha_check_answer ($privatekey,
$_SERVER["REMOTE_ADDR"],
$_POST["recaptcha_challenge_field"],
$_POST["recaptcha_response_field"]);
if (!$resp->is_valid)
$errCapt='<p style="color:#D6012C ">The CAPTCHA Code wasnot entered correctly.</p>';
【问题讨论】:
检查是否已填写。if( strlen($_POST['recaptcha_challenge_field']) > 0)
感谢您的回复,但请您提供更多详细信息...
我刚刚在联系表单上实现了这一点。我建议使用新的 Google 提供的 recaptchalib.php
以及他们在此链接上的示例:github.com/google/ReCAPTCHA/tree/master/php
谢谢你,但很抱歉我还不明白,我有两个文件contact.html和contact.php,第一个调用第二个,在第一个我放了以下内容:在 :
但在contact.php中我不知道我应该放什么??
【参考方案1】:
私钥安全
虽然这里的答案肯定有效,但他们正在使用GET
请求,该请求会公开您的私钥(即使使用了https
)。在Google Developers 上,指定的方法是POST
。
更多细节:https://***.com/a/323286/1680919
通过 POST 验证
function isValid()
try
$url = 'https://www.google.com/recaptcha/api/siteverify';
$data = ['secret' => '[YOUR SECRET KEY]',
'response' => $_POST['g-recaptcha-response'],
'remoteip' => $_SERVER['REMOTE_ADDR']];
$options = [
'http' => [
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data)
]
];
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
return json_decode($result)->success;
catch (Exception $e)
return null;
数组语法:我使用“新”数组语法([
和 ]
而不是 array(..)
)。如果您的 php 版本尚不支持此功能,则必须相应地编辑这 3 个数组定义(请参阅注释)。
返回值: 如果用户有效,此函数返回true
,如果无效,则返回false
,如果发生错误,则返回null
。例如,您可以通过编写 if (isValid()) ...
【讨论】:
如果您需要旧数组语法,请将$data = ...
和$options = ...
声明更改为:$data = array('secret' => '[YOUR SECRET KEY]', 'response' => $_POST['g-recaptcha-response'], 'remoteip' => $_SERVER['REMOTE_ADDR']); $options = array( 'http' => array( 'header' => "Content-type: application/x-www-form-urlencoded\r\n", 'method' => 'POST', 'content' => http_build_query($data) ) );
您可以将请求保存到服务器并提前保释:if (empty($_POST['g-recaptcha-response'])) return false;
https url实际上是加密的,所以即使使用GET请求也不会暴露私钥,请参阅:***.com/questions/499591/are-https-urls-encrypted
请注意,出于调试目的,您只能调用一次isValid()
。如果第二次调用,它将返回 false。用 echo 语句很难发现这一点......
没有使用的函数抛出异常,因此 trycatch() 毫无意义【参考方案2】:
这是解决方案
index.html
<html>
<head>
<title>Google recapcha demo - Codeforgeek</title>
<script src='https://www.google.com/recaptcha/api.js'></script>
</head>
<body>
<h1>Google reCAPTHA Demo</h1>
<form id="comment_form" action="form.php" method="post">
<input type="email" placeholder="Type your email" size="40"><br><br>
<textarea name="comment" rows="8" cols="39"></textarea><br><br>
<input type="submit" name="submit" value="Post comment"><br><br>
<div class="g-recaptcha" data-sitekey="=== Your site key ==="></div>
</form>
</body>
</html>
验证.php
<?php
$email; $comment; $captcha;
if(isset($_POST['email']))
$email=$_POST['email'];
if(isset($_POST['comment']))
$comment=$_POST['comment'];
if(isset($_POST['g-recaptcha-response']))
$captcha=$_POST['g-recaptcha-response'];
if(!$captcha)
echo '<h2>Please check the the captcha form.</h2>';
exit;
$response = json_decode(file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=YOUR SECRET KEY&response=".$captcha."&remoteip=".$_SERVER['REMOTE_ADDR']), true);
if($response['success'] == false)
echo '<h2>You are spammer ! Get the @$%K out</h2>';
else
echo '<h2>Thanks for posting comment.</h2>';
?>
http://codeforgeek.com/2014/12/google-recaptcha-tutorial/
【讨论】:
reCAPTCHA 表单字段值直接连接到验证 URL。攻击者可以使用它在验证请求中注入任意表单参数,从而可能绕过 CAPTCHA。要解决此问题,请像这样清理验证码变量:urlencode($captcha)
此代码未编码可被攻击者用来破坏您的代码的参数。
数据应按照指定的in the docs 发布。此代码使用 GET 方法。我会选择Levit's answer 的变体。
对我来说效果很好。除了表单行(在 index.html 中):action="form.php"
,它应该是action="verify.php"
。
此代码适用于我的共享主机而不适用于 VPS 服务器。是否有任何与服务器相关的要求?【参考方案3】:
我不喜欢任何这些解决方案。我改用这个:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://www.google.com/recaptcha/api/siteverify");
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, [
'secret' => $privatekey,
'response' => $_POST['g-recaptcha-response'],
'remoteip' => $_SERVER['REMOTE_ADDR']
]);
$resp = json_decode(curl_exec($ch));
curl_close($ch);
if ($resp->success)
// Success
else
// failure
我认为这是优越的,因为您确保它被发布到服务器并且它不会进行尴尬的“file_get_contents”调用。这与此处描述的 recaptcha 2.0 兼容:https://developers.google.com/recaptcha/docs/verify
我觉得这个更清洁。我看到大多数解决方案都是 file_get_contents,当我觉得 curl 就足够了。
【讨论】:
如果由于 php.ini 中禁用了“allow_url_fopen”而无法使用 file_get_contents(),这是一个很好的解决方案。为我工作。 +1。 简单明了,按照谷歌的要求使用POST【参考方案4】:简单且最佳的解决方案如下。index.html
<form action="submit.php" method="POST">
<input type="text" name="name" value="" />
<input type="text" name="email" value="" />
<textarea type="text" name="message"></textarea>
<div class="g-recaptcha" data-sitekey="Insert Your Site Key"></div>
<input type="submit" name="submit" value="SUBMIT">
</form>
提交.php
<?php
if(isset($_POST['submit']) && !empty($_POST['submit']))
if(isset($_POST['g-recaptcha-response']) && !empty($_POST['g-recaptcha-response']))
//your site secret key
$secret = 'InsertSiteSecretKey';
//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)
//contact form submission code goes here
$succMsg = 'Your contact request have submitted successfully.';
else
$errMsg = 'Robot verification failed, please try again.';
else
$errMsg = 'Please click on the reCAPTCHA box.';
?>
我从这里找到了这个参考和完整的教程 - Using new Google reCAPTCHA with PHP
【讨论】:
【参考方案5】:我喜欢 Levit 的回答并最终使用了它。但我只是想指出,以防万一,有一个用于新 reCAPTCHA 的官方 Google PHP 库:https://github.com/google/recaptcha
最新版本(现在是 1.1.2)支持 Composer,并包含一个示例,您可以运行该示例来查看您是否已正确配置所有内容。
您可以在下面看到这个官方库附带的部分示例(为了清楚起见,我做了一些小的修改):
// Make the call to verify the response and also pass the user's IP address
$resp = $recaptcha->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']);
if ($resp->isSuccess())
// If the response is a success, that's it!
?>
<h2>Success!</h2>
<p>That's it. Everything is working. Go integrate this into your real project.</p>
<p><a href="/">Try again</a></p>
<?php
else
// If it's not successful, then one or more error codes will be returned.
?>
<h2>Something went wrong</h2>
<p>The following error was returned: <?php
foreach ($resp->getErrorCodes() as $code)
echo '<tt>' , $code , '</tt> ';
?></p>
<p>Check the error code reference at <tt><a href="https://developers.google.com/recaptcha/docs/verify#error-code-reference">https://developers.google.com/recaptcha/docs/verify#error-code-reference</a></tt>.
<p><strong>Note:</strong> Error code <tt>missing-input-response</tt> may mean the user just didn't complete the reCAPTCHA.</p>
<p><a href="/">Try again</a></p>
<?php
希望对某人有所帮助。
【讨论】:
【参考方案6】:在上面的例子中。对我来说,这 if($response.success==false)
的东西不起作用。这是正确的 PHP 代码:
$url = 'https://www.google.com/recaptcha/api/siteverify';
$privatekey = "--your_key--";
$response = file_get_contents($url."?secret=".$privatekey."&response=".$_POST['g-recaptcha-response']."&remoteip=".$_SERVER['REMOTE_ADDR']);
$data = json_decode($response);
if (isset($data->success) AND $data->success==true)
// everything is ok!
else
// spam
【讨论】:
这是因为您没有将true
作为第二个参数传递给json_decode
。默认情况下,json_decode
返回一个对象 (jsOn),但传递 true
将允许它返回一个数组。
“在上面的示例中...” 请注意,StackExchange 平台根据投票排名对答案进行排序。上面的例子显然不是你所指的那个。【参考方案7】:
使用 PHP 在服务器端进行验证。您需要考虑两件最重要的事情。
1. $_POST['g-recaptcha-response']
2.$secretKey = '6LeycSQTAAAAAMM3AeG62pBslQZwBTwCbzeKt06V';
$verifydata = file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret='.$secretKey.'&response='.$_POST['g-recaptcha-response']);
$response= json_decode($verifydata);
如果你得到 $verifydata true,你完成了。 欲了解更多信息,请查看此 Google reCaptcha Using PHP | Only 2 Step Integration
【讨论】:
【参考方案8】:它与 mattgen88 类似,但我只是修复了 CURLOPT_HEADER,并重新定义了数组以使其在 domain.com 主机服务器中工作。这个在我的 xampp localhost 上不起作用。那些小错误却花了很长时间才弄清楚。此代码已在 domain.com 托管上进行了测试。
$privatekey = 'your google captcha private key';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://www.google.com/recaptcha/api/siteverify");
curl_setopt($ch, CURLOPT_HEADER, 'Content-Type: application/json');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, array(
'secret' => $privatekey,
'response' => $_POST['g-recaptcha-response'],
'remoteip' => $_SERVER['REMOTE_ADDR']
)
);
$resp = json_decode(curl_exec($ch));
curl_close($ch);
if ($resp->success)
// Success
echo 'captcha';
else
// failure
echo 'no captcha';
【讨论】:
【参考方案9】:这里有一个简单的例子。请记住从 google api 提供 secretKey 和 siteKey。
<?php
$siteKey = 'Provide element from google';
$secretKey = 'Provide element from google';
if($_POST['submit'])
$username = $_POST['username'];
$responseKey = $_POST['g-recaptcha-response'];
$userIP = $_SERVER['REMOTE_ADDR'];
$url = "https://www.google.com/recaptcha/api/siteverify?secret=$secretKey&response=$responseKey&remoteip=$userIP";
$response = file_get_contents($url);
$response = json_decode($response);
if($response->success)
echo "Verification is correct. Your name is $username";
else
echo "Verification failed";
?>
<html>
<meta>
<title>Google ReCaptcha</title>
</meta>
<body>
<form action="index.php" method="post">
<input type="text" name="username" placeholder="Write your name"/>
<div class="g-recaptcha" data-sitekey="<?= $siteKey ?>"></div>
<input type="submit" name="submit" value="send"/>
</form>
<script src='https://www.google.com/recaptcha/api.js'></script>
</body>
【讨论】:
【参考方案10】:Source Tutorial Link
Google reCAPTCHA的V2。
第 1 步 - 转至 Google reCAPTCHA
登录然后获取Site Key和Secret Key
第 2 步 - 下载 PHP 代码 here 并在您的服务器上上传 src 文件夹。
第 3 步 - 在 form.php
中使用以下代码
<head>
<title>FreakyJolly.com Google reCAPTCHA EXAMPLE form</title>
<script src='https://www.google.com/recaptcha/api.js'></script>
</head>
<body>
<?php
require('src/autoload.php');
$siteKey = '6LegPmIUAAAAADLwDmXXXXXXXyZAJVJXXXjN';
$secret = '6LegPmIUAAAAAO3ZTXXXXXXXXJwQ66ngJ7AlP';
$recaptcha = new \ReCaptcha\ReCaptcha($secret);
$gRecaptchaResponse = $_POST['g-recaptcha-response']; //google captcha post data
$remoteIp = $_SERVER['REMOTE_ADDR']; //to get user's ip
$recaptchaErrors = ''; // blank varible to store error
$resp = $recaptcha->verify($gRecaptchaResponse, $remoteIp); //method to verify captcha
if ($resp->isSuccess())
/********
Add code to create User here when form submission is successful
*****/
else
/****
// This variable will have error when reCAPTCHA is not entered correctly.
****/
$recaptchaErrors = $resp->getErrorCodes();
?>
<form autcomplete="off" class="form-createuser" name="create_user_form" action="" method="post">
<div class="panel periodic-login">
<div class="panel-body text-center">
<div class="form-group form-animate-text" style="margin-top:40px !important;">
<input type="text" autcomplete="off" class="form-text" name="new_user_name" required="">
<span class="bar"></span>
<label>Username</label>
</div>
<div class="form-group form-animate-text" style="margin-top:40px !important;">
<input type="text" autcomplete="off" class="form-text" name="new_phone_number" required="">
<span class="bar"></span>
<label>Phone</label>
</div>
<div class="form-group form-animate-text" style="margin-top:40px !important;">
<input type="password" autcomplete="off" class="form-text" name="new_user_password" required="">
<span class="bar"></span>
<label>Password</label>
</div>
<?php
if(isset($recaptchaErrors[0]))
print('Error in Submitting Form. Please Enter reCAPTCHA AGAIN');
?>
<div class="g-recaptcha" data-sitekey="6LegPmIUAAAAADLwDmmVmXXXXXXXXXXXXXXjN"></div>
<input type="submit" class="btn col-md-12" value="Create User">
</div>
</div>
</form>
</body>
</html>
【讨论】:
【参考方案11】:针对@mattgen88的回答,这里有一个排列更好的CURL方法:
//$secret= 'your google captcha private key';
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://www.google.com/recaptcha/api/siteverify",
CURLOPT_HEADER => "Content-Type: application/json",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => FALSE, // to disable ssl verifiction set to false else true
//CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => array(
'secret' => $secret,
'response' => $_POST['g-recaptcha-response'],
'remoteip' => $_SERVER['REMOTE_ADDR']
)
));
$response = json_decode(curl_exec($curl));
$err = curl_error($curl);
curl_close($curl);
if ($response->success)
echo 'captcha';
else if ($err)
echo $err;
else
echo 'no captcha';
【讨论】:
【参考方案12】:查看以下示例
<script src='https://www.google.com/recaptcha/api.js'></script>
<script>
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;
else
document.getElementById('captcha').innerHTML="Captcha completed";
return true;
</script>
<form autocomplete="off" method="post" action=submit.php">
<input type="text" name="name">
<input type="text" name="email">
<div class="g-recaptcha" id="rcaptcha" data-sitekey="site key"></div>
<span id="captcha" style="color:red" /></span> <!-- this will show captcha errors -->
<input type="submit" id="sbtBrn" value="Submit" name="sbt" class="btn btn-info contactBtn" />
</form>
【讨论】:
以上是关于如何在服务器端验证 Google reCAPTCHA v3?的主要内容,如果未能解决你的问题,请参考以下文章
使用 Google 登录 - 我们如何在 .net 中验证 Google ID 令牌服务器端?缺少代码示例,库似乎已弃用
如何使用适用于 android 的 google play 游戏服务实现后端服务器身份验证
如何使用 Node 服务器验证 Android Google 登录