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

Google reCAPTCHA Enterprise未拦截Puppeteer自动化请求问题咨询

分析reCAPTCHA Enterprise未拦截Puppeteer脚本的原因及解决方案

核心原因分析

reCAPTCHA Enterprise的评分系统依赖多维度信号(浏览器指纹、交互行为、IP环境、会话模式等)综合判断,你的脚本能拿到0.8高分,大概率是因为没有触发足够的高风险特征:

  1. Puppeteer交互行为接近真人
    脚本使用page.type()模拟真实打字输入(默认带按键延迟),而非直接修改DOM值;每次提交后等待页面加载完成,这种操作节奏和真人差异极小,reCAPTCHA难以通过行为模式区分。

  2. 无头浏览器特征弱化
    新版Chrome的无头模式(headless: true)和普通浏览器的指纹差异大幅缩小,没有旧版无头模式特有的机器人标识(比如特殊User-Agent字段),reCAPTCHA的指纹检测模块无法识别。

  3. 缺少高风险触发信号
    脚本的循环操作未触及reCAPTCHA的异常规则:

    • 没有短时间内高频提交(每次迭代都有页面跳转和等待,间隔足够)
    • IP地址未被标记为恶意/代理IP
    • 用户名/密码的规律格式未达到reCAPTCHA预设的异常阈值
  4. reCAPTCHA配置未针对性优化

    • 可能未针对登录场景设置严格的评分阈值(默认阈值通常为0.5,0.8远高于此)
    • 未启用会话跟踪、异常行为检测等高级模块,无法识别同一浏览器的连续登录尝试

解决方案建议

1. 强化reCAPTCHA Enterprise检测能力

  • 在Google Cloud控制台的reCAPTCHA Enterprise面板,针对你的site key:
    • 调整风险评分阈值:将登录场景的阈值设为0.7或更高,低于该分数的请求直接拦截
    • 启用高级检测功能:开启「会话分析」「异常行为检测」,针对同一IP/浏览器的重复登录、规律用户名等行为增加额外风险权重
  • 确保前端reCAPTCHA标签的action参数与后端验证一致(比如登录页设为action="login",后端recaptchaAction也传login),让reCAPTCHA针对场景精准评分

2. 优化后端验证逻辑

  • 除了评分,结合riskAnalysis.reasons判断:如果返回AUTOMATION等机器人相关原因,即使评分较高也拒绝请求
  • 补充额外防护规则:比如拦截格式规律的用户名(如autotester 1这种带序号的格式),限制同一IP的每日登录次数

3. 测试并暴露机器人特征

  • 修改脚本,加入明显的机器人行为,观察评分是否下降:
    // 直接设置输入框值,而非模拟打字
    await page.$eval('input[name="login"]', el => el.value = `autotester ${i}`);
    await page.$eval('input[name="password"]', el => el.value = 'autotesterpassword');
    // 无延迟快速提交
    await page.click('button[type="submit"]', { delay: 0 });
    
  • 使用旧版无头模式(headless: "old"),或修改浏览器指纹(比如禁用WebGL、调整User-Agent),验证reCAPTCHA的检测逻辑是否正常

4. 验证后端代码逻辑

检查createAssessment函数:

  • 确认recaptchaAction参数与前端reCAPTCHA的action完全匹配
  • 不要忽略response.riskAnalysis.reasons中的关键提示,某些场景下即使评分高,也可能存在潜在风险信号

附用户提供的代码

后端reCAPTCHA验证代码

async function createAssessment({ projectID, recaptchaKey, token, recaptchaAction }) {
const client = new RecaptchaEnterpriseServiceClient();
const projectPath = client.projectPath(projectID);
const target_event = {
    'token': token,
    siteKey: recaptchaKey
};

const request = {
    assessment: {
        event: target_event
    },
    parent: projectPath,
};

console.log('Creating assessment...');
const [response] = await client.createAssessment(request);
console.log('Assessment created.');

if (!response.tokenProperties.valid) {
    console.log(`The CreateAssessment call failed because the token was: ${response.tokenProperties.invalidReason}`);
    return { score: null, failReason: response.tokenProperties.invalidReason };
}

if (response.tokenProperties.action === recaptchaAction) {
    console.log(`The reCAPTCHA score is: ${response.riskAnalysis.score}`);
    response.riskAnalysis.reasons.forEach((reason) => {
        console.log(reason);
    });

    return { score: response.riskAnalysis.score, failReason: null };
} else {
    console.log("The action attribute in your reCAPTCHA tag does not match the action you are expecting to score");
    return { score: null, failReason: "The action attribute in your reCAPTCHA tag does not match the action you are expecting to score" };
}
}

Puppeteer自动化脚本代码

const puppeteer = require('puppeteer');
async function run() {
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
for (let i = 1; i <= 50; i++) {
    try {
        console.log(`Processing iteration ${i}`);

        // Navigate to the website
        console.log(`Iteration ${i}: Navigating to the website`);
        await page.goto('https://my-domain.com/');

        // Enter the username
        console.log(`Iteration ${i}: Entering the username`);
        await page.type('input[name="login"]', `autotester ${i}`);

        // Enter the password
        console.log(`Iteration ${i}: Entering the password`);
        await page.type('input[name="password"]', 'autotesterpassword');

        // Click the submit button
        console.log(`Iteration ${i}: Clicking the submit button`);
        await page.click('button[type="submit"]');

        // Wait for the page to load after submitting the form
        console.log(`Iteration ${i}: Waiting for the page to load`);
        await page.waitForSelector('#loadingDialog', { hidden: true });

        // Take a screenshot or perform further actions if needed
        console.log(`Iteration ${i}: Taking a screenshot`);
        await page.screenshot({ path: `screenshot_${i}.png` });

        console.log(`Iteration ${i} completed successfully`);
    } catch (error) {
        console.error(`Error occurred in iteration ${i}:`, error);
    }
}

// Close the browser
await browser.close();}run().catch(error => console.error(error));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 13:44:51