You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PHP服务端正确实现reCAPTCHA (v3)请求验证

reCAPTCHA v3 服务端校验正确实现方案

你当前代码持续收到垃圾提交、校验逻辑不生效,核心是代码里存在几个显性错误,以下是问题排查和可直接复用的实现:

现有代码的核心问题

  • 接口请求参数拼接错误:拼接谷歌校验接口地址时,错误使用了HTML转义字符&代替URL参数连接符&,导致secret、response两个核心参数没有正确传递给校验接口,校验逻辑完全没生效。
  • 缺少必要校验维度:没有传递用户端真实IP、没有校验返回结果的hostname字段,容易被跨站盗用密钥生成的无效token绕过。
  • 无异常处理逻辑:当服务器无法连通谷歌校验接口时,file_get_contents会直接返回false,后续json_decode操作会报错,既无法正常校验也无法定位问题。
  • 邮件头逻辑错误:第二行$headers赋值直接覆盖了上一行设置的From头,容易导致发出的邮件被服务商判定为垃圾邮件拒收。
  • 前端回调未绑定:你定义了onSubmit提交回调,但没有在提交按钮上绑定对应属性,偶发会出现点击按钮无响应的问题。

修正后的完整代码

前端部分(HTML+JS)

<script src="https://www.google.com/recaptcha/api.js"></script>
<script>
function onSubmit(token) {
  document.getElementById("contact-form").submit();
}
</script>

<div>
<form id="contact-form" method="post" action="sendmail.php" role="form">
    <input type="text" placeholder="Naam" class="form-control" name="name" id="name" required>
    <input type="email" placeholder="Email" class="form-control" name="email" id="email" required>
    <textarea rows="6" placeholder="Bericht" class="form-control" name="description" id="description" required></textarea>   

    <div id="cf-submit">
        <input  type="submit" 
                id="contact-submit" 
                class="btn btn-transparent g-recaptcha"  
                data-sitekey="替换为你的站点公钥" 
                data-action='submit'
                data-callback="onSubmit"
                value="Verzend"
                data-badge="inline"
        >
    </div>
</form>
</div>

注:给输入项加了required属性做基础的前端非空校验,减少无效请求。

后端部分(sendmail.php)

优先使用cURL发起校验请求(比file_get_contents稳定性更高、超时可控),代码如下:

<?php
session_start();

// 仅接受POST请求
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    exit('仅支持POST请求');
}

// 基础参数校验
if (empty($_POST['g-recaptcha-response']) || empty($_POST['name']) || empty($_POST['email']) || empty($_POST['description'])) {
    exit('参数不完整');
}

// 配置项
$recaptcha_secret = '替换为你的v3专属私钥'; // 注意v2和v3的密钥不通用
$score_threshold = 0.5; // 阈值可根据实际拦截效果调整,垃圾多就调高到0.6-0.7,误拦多就降到0.4
$allow_action = 'submit'; // 和前端data-action配置的值保持一致
$allow_hostname = $_SERVER['HTTP_HOST']; // 仅允许你自己站点的请求通过校验
$email_to = 'mail@mail.com';

// 发起reCAPTCHA校验请求
$ch = curl_init('https://www.google.com/recaptcha/api/siteverify');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, [
    'secret' => $recaptcha_secret,
    'response' => $_POST['g-recaptcha-response'],
    'remoteip' => $_SERVER['REMOTE_ADDR'] // 传递用户真实IP,提升校验准确率
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
$response = curl_exec($ch);
$curl_errno = curl_errno($ch);
curl_close($ch);

// 接口请求异常处理
if ($curl_errno || !$response) {
    // 可在此处加日志记录,方便排查网络问题
    exit('校验服务暂时不可用,请稍后重试');
}

$recaptcha_result = json_decode($response, true);

// 全维度校验
$verify_pass = $recaptcha_result['success'] === true
    && $recaptcha_result['score'] >= $score_threshold
    && $recaptcha_result['action'] === $allow_action
    && $recaptcha_result['hostname'] === $allow_hostname;

if (!$verify_pass) {
    // 可临时打印$recaptcha_result查看具体失败原因,正式环境注释掉
    // var_dump($recaptcha_result);
    exit('请求校验失败,疑似垃圾提交');
}

// 校验通过,发送邮件
$name = strip_tags($_POST['name']);
$email = filter_var($_POST['email'], FILTER_SANITIZE_EMAIL);
$subject = '来自网站联系表单的消息:' . $name;
$message = strip_tags($_POST['description']);

// 修正邮件头,避免覆盖
$headers  = "From: 网站表单 <no-reply@" . $_SERVER['HTTP_HOST'] . ">\r\n";
$headers .= "Reply-To: " . $email . "\r\n";
$headers .= "Content-Type: text/plain; charset=utf-8\r\n";

if(mail($email_to, $subject, $message, $headers)){
    echo 'sent';      
}else{
    echo '邮件发送失败';   
}
?>

有效性测试方法

  • 拦截逻辑测试:直接用POST工具构造请求,不带g-recaptcha-response参数、或者随便填无效的response值,请求sendmail.php应该直接返回校验失败,不会发信。
  • 正常流程测试:在浏览器正常打开表单页,填写内容提交,应正常收信;测试阶段可以临时打开代码里的var_dump($recaptcha_result)注释,查看返回的success、score、action、hostname字段是否符合预期,正常用户操作得分一般在0.7以上。
  • 阈值校准:累计10-20次正常提交的得分,再观察垃圾提交的得分,把阈值设在两类得分的区间中间即可,平衡拦截率和误拦率。

注意:reCAPTCHA v3是无交互校验,没有100%的拦截率,如果垃圾提交量特别大,可以搭配表单提交频率限制、隐藏蜜罐字段等方式进一步提升防护效果。

内容的提问来源于stack exchange,提问作者Yoorizz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 20:54:34