排查Invisible reCaptcha失效、表单可直接提交的问题与测试方法
代码问题定位
前端逻辑的可利用漏洞
- 你在reCaptcha回调里直接调用
form.submit()时,这个原生方法会完全绕过你绑定的所有submit事件监听器。攻击者只需要在DevTools里直接调用这个原生提交方法,根本不会触发你写的“检查是否有captcha响应”的判断逻辑,这就是为什么你用模拟Googlebot的方式能成功提交、还收到几十封垃圾邮件的核心原因。 - 哪怕是正常流程下,reCaptcha校验通过后走的原生
form.submit()也没有把验证响应值传递到服务端,服务端根本拿不到验证结果,等于完全没起到校验作用。
缺失核心的服务端校验
所有前端的JS校验都可以被轻松绕过:bot不需要加载你的页面JS,直接向
scripts/mail.php发POST请求就能提交数据。你现在的代码完全没有在服务端对接reCaptcha的校验环节,整个防护是完全暴露的,就算前端逻辑写得再严谨,也挡不住直接打接口的bot。
细节隐患
- 你用
async defer加载reCaptcha脚本时,存在加载时序问题:如果用户在组件加载完成前点击提交,直接调用grecaptcha.getResponse()会抛出未定义的JS错误,因为错误发生在事件回调里,很容易被忽略,导致提交逻辑直接中断。 - 全局挂载的
onCompleted函数没有做作用域隔离,很容易被页面其他脚本覆盖,导致reCaptcha的回调根本不触发。
可直接落地的修正方案
前端代码调整
<head> <!-- 替换为你自己的站点key,指定render参数实现显式初始化 --> <script src="https://www.google.com/recaptcha/api.js?render=你的站点key" async defer></script> </head> <body> <form method="post" action="scripts/mail.php" id="contact-form"> <input type="text" name="input" placeholder="Some input fields"> <button type="submit">Send</button> </form> <script> const contactForm = document.getElementById('contact-form'); // 统一的最终提交逻辑,避免重复写校验 const submitForm = () => { // 提交前二次校验captcha响应 const captchaToken = grecaptcha.getResponse(); if (!captchaToken) return; // 把captcha token挂载到表单,随请求发给服务端 const hiddenToken = document.createElement('input'); hiddenToken.type = 'hidden'; hiddenToken.name = 'g-recaptcha-response'; hiddenToken.value = captchaToken; contactForm.appendChild(hiddenToken); // 正式提交 contactForm.submit(); } contactForm.addEventListener('submit', (e) => { e.preventDefault(); // 先处理组件未加载完成的异常 if (typeof grecaptcha === 'undefined') { alert('安全验证组件加载中,请稍后重试'); return; } // 已有有效验证的情况直接提交 if (grecaptcha.getResponse()) { submitForm(); return; } // 触发invisible reCaptcha校验,通过后执行提交 grecaptcha.ready(() => { grecaptcha.execute('你的站点key', {action: 'contact_submit'}).then(() => { submitForm(); }) }) }) </script> </body>
服务端强制校验要求
- 前端把
g-recaptcha-response字段传给服务端后,服务端必须使用自己的reCaptcha密钥,校验该token的合法性、来源站点是否匹配、风险评分是否达到你设置的阈值。 - 只有服务端校验完全通过的请求,才能执行后续发邮件的逻辑,这是拦截bot的核心防线,没有这个环节所有前端防护都形同虚设。
reCaptcha生效性的验证方法
- 前端拦截验证:打开DevTools控制台,手动执行
document.getElementById('contact-form').submit(),正常情况下该调用会被绑定的submit事件拦截,不会直接发出请求。 - 接口防护验证:用接口工具直接向
scripts/mail.php发送不带g-recaptcha-response字段的POST请求,正常情况下服务端会直接拒绝执行发信操作,返回错误提示,不会真正发送邮件。 - 后台数据验证:登录reCaptcha管理后台,看对应站点的请求统计,正常真人提交的请求会有对应动作标识,风险评分大多在0.7以上,bot请求的评分会低于0.3,且不会带上合法的action标识。
内容的提问来源于stack exchange,提问作者KimMai
相关产品推荐
相关产品推荐

