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

Chrome扩展MV3:沙箱iframe中reCAPTCHA WebWorker加载失败(源为'null')

解决Chrome扩展Manifest V3中reCAPTCHA v3的WebWorker加载错误

问题场景

开发Manifest V3版本的Chrome扩展时,弹窗页面需要集成Google reCAPTCHA v3。由于MV3禁止扩展页面直接加载外部脚本,采用官方沙箱方案,通过iframe将reCAPTCHA加载到沙箱化的HTML文件中。页面能显示reCAPTCHA徽章,且onloadCallback正常执行,但控制台抛出以下错误:

Uncaught SecurityError: Failed to construct 'Worker':
  Script at 
  'https://www.google.com/recaptcha/api2/webworker.js?hl=en&v=…'
  cannot be accessed from origin 'null'.

相关配置代码

manifest.json

{
  "manifest_version": 3,
  …
  "permissions": ["declarativeNetRequest", "scripting", "storage", "tabs", "unlimitedStorage"],
  "host_permissions": [
    "https://www.google.com/*",
    "https://www.gstatic.com/*",
    "https://recaptcha.google.com/*",
    "https://recaptcha.net/*",
    ...
  ],
  "content_security_policy": {
    "sandbox": "sandbox allow-scripts allow-forms allow-popups allow-modals;
               script-src 'self' 'unsafe-inline' https://www.google.com/
               https://www.gstatic.com/ https://recaptcha.google.com/ 
               https://recaptcha.net/; child-src 'self';"
  },
  "sandbox": {
    "pages": ["recaptcha_sandbox.html"]
  },
  "background": { "service_worker": "background.js" },
  "web_accessible_resources": [
    { "resources": ["recaptcha_sandbox.html"], "matches": ["<all_urls>"] }
  ],
  …
}

recaptcha_sandbox.html

<!DOCTYPE html>
<html>
  <body>
    <script src="https://www.google.com/recaptcha/api.js?
                    onload=onloadCallback&render=MY_SITE_KEY" defer>
    </script>
    <script>
      function onloadCallback() {
        console.log('RECAPTCHA_READY ')
    
        window.grecaptcha.ready(async () => {
          try {
            const token = await window.grecaptcha.execute(
              'MY_SITE_KEY',
              { action: 'login' }
            );
            console.log('TOKEN', token);
          } catch (err) {
            console.error('ERROR', err);
          }
        });
      }
    </script>
  </body>
</html>

弹窗React代码

function LoginForm() {
  ...

  return (
    ...
    <iframe
      ref={iframeRef}
      src={chrome.runtime.getURL('recaptcha_sandbox.html')}
      style={{
        position: 'absolute',
        top: 0,
        left: 0,
        width: '100%',
        height: '100%',
        border: 'none',
        zIndex: -1,
        pointerEvents: 'none'
      }}
      title="reCAPTCHA Sandbox"
    />
    ...

  );
}

错误原因

  1. MV3的沙箱页面默认使用null origin,浏览器同源策略禁止null origin加载跨域Worker脚本。
  2. 当前CSP的sandbox指令未显式允许Worker创建,且缺少worker-src规则授权reCAPTCHA域名加载Worker脚本。
  3. 不必要的web_accessible_resources配置可能引发额外的安全限制(扩展内部页面无需对外暴露沙箱页面)。

修复方案

1. 更新Manifest的CSP沙箱配置

修改content_security_policy中的sandbox规则,添加allow-worker指令,并新增worker-src授权reCAPTCHA相关域名:

"content_security_policy": {
  "sandbox": "sandbox allow-scripts allow-forms allow-popups allow-modals allow-worker;
             script-src 'self' 'unsafe-inline' https://www.google.com/ https://www.gstatic.com/ https://recaptcha.google.com/ https://recaptcha.net/;
             worker-src https://www.google.com/ https://www.gstatic.com/ https://recaptcha.google.com/ https://recaptcha.net/;"
}

2. 移除不必要的资源暴露

从web_accessible_resources中删除recaptcha_sandbox.html的配置,因为弹窗属于扩展内部页面,直接通过chrome.runtime.getURL访问沙箱页面无需对外暴露:

// 删除以下配置
"web_accessible_resources": [
  { "resources": ["recaptcha_sandbox.html"], "matches": ["<all_urls>"] }
]

3. 完善沙箱与弹窗的通信逻辑

沙箱页面获取token后,通过postMessage传递到弹窗页面,弹窗监听消息接收token:

修正后的recaptcha_sandbox.html

<!DOCTYPE html>
<html>
  <body>
    <script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=MY_SITE_KEY" defer></script>
    <script>
      function onloadCallback() {
        console.log('RECAPTCHA_READY ')
    
        window.grecaptcha.ready(async () => {
          try {
            const token = await window.grecaptcha.execute(
              'MY_SITE_KEY',
              { action: 'login' }
            );
            console.log('TOKEN', token);
            // 向弹窗页面发送token,限制接收方为扩展内部域名
            window.parent.postMessage(
              { type: 'RECAPTCHA_TOKEN', token },
              chrome.runtime.getURL('/')
            );
          } catch (err) {
            console.error('ERROR', err);
          }
        });
      }
    </script>
  </body>
</html>

弹窗React代码添加消息监听

import { useEffect } from 'react';

function LoginForm() {
  useEffect(() => {
    const handleRecaptchaToken = (event) => {
      // 验证消息来源和类型,确保安全
      if (event.origin === chrome.runtime.getURL('/') && event.data.type === 'RECAPTCHA_TOKEN') {
        const token = event.data.token;
        console.log('Received reCAPTCHA token:', token);
        // 在这里处理token的后续逻辑(如提交登录请求)
      }
    };

    window.addEventListener('message', handleRecaptchaToken);
    return () => window.removeEventListener('message', handleRecaptchaToken);
  }, []);

  return (
    ...
    <iframe
      ref={iframeRef}
      src={chrome.runtime.getURL('recaptcha_sandbox.html')}
      style={{
        position: 'absolute',
        top: 0,
        left: 0,
        width: '100%',
        height: '100%',
        border: 'none',
        zIndex: -1,
        pointerEvents: 'none'
      }}
      title="reCAPTCHA Sandbox"
    />
    ...
  );
}

验证效果

重新加载扩展后,沙箱页面能正常加载reCAPTCHA的WebWorker,控制台不再抛出SecurityError,且弹窗能成功接收reCAPTCHA token。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 05:07:10