Manifest V3扩展向data URI iframe注入脚本报web_accessible_resources错误
问题根因
这不是配置错误,也不是偶发bug,是Chrome对Manifest V3扩展的既定安全限制:
data:URI格式的iframe属于不透明源(opaque origin),对应的window.origin值为nullweb_accessible_resources的匹配规则(即使配置为<all_urls>)不会对这类无有效宿主的null源开放chrome-extension://协议资源的加载权限- 原逻辑是在页面主世界插入带扩展资源src的script标签,该请求由null源的页面上下文发起,会直接被Chrome的安全策略拦截,触发报错。非data URI的常规源因为能被WAR规则匹配,所以可以正常加载。
可用替代方案
优先选择第一种方案,改动最小、兼容性最好,不需要额外申请权限。
方案1:内联注入脚本内容(推荐)
核心逻辑是避开主世界发起chrome-extension://请求的环节:在content script的隔离上下文先读取扩展内payload脚本的文本内容,再直接以内联形式插入到页面主世界,完全绕开WAR校验逻辑。
不需要修改现有manifest配置,直接替换content-script.js代码即可:
// 隔离上下文内请求扩展资源不受WAR规则限制 fetch(chrome.runtime.getURL('/src/dest/payload-min.js')) .then(resp => resp.text()) .then(payloadCode => { const script = document.createElement('script') script.className = 'myScriptClass' // 直接写入脚本内容,不设置src属性 script.textContent = payloadCode const injectTarget = document.head || document.documentElement injectTarget.appendChild(script) // 注入执行完成后可移除标签,减少DOM冗余 script.remove() })
该方案在所有frame类型(常规源iframe、data URI iframe、about:blank iframe)下均可正常运行。
方案2:使用chrome.scripting API直接注入主世界
如果不想用内联注入的形式,可以用MV3原生的脚本注入API,直接把payload注入到页面主世界,不需要手动创建script标签,也不依赖WAR配置。
首先修改manifest.json:
- 在
permissions数组中新增"scripting"权限 - 确保
host_permissions包含"<all_urls>"(当前配置已满足)
之后修改content-script.js逻辑,针对data URI源走API注入逻辑:
// data:、about:blank等特殊源的origin均为null const isSpecialOrigin = window.origin === 'null' if (isSpecialOrigin) { // 获取当前tab信息,向当前帧注入主世界脚本 chrome.tabs.getCurrent(tab => { chrome.runtime.sendMessage({type: 'getFrameId'}, resp => { chrome.scripting.executeScript({ target: { tabId: tab.id, frameIds: [resp.frameId] }, files: ['/src/dest/payload-min.js'], world: 'MAIN', injectImmediately: true }) }) }) } else { // 常规源保留原有逻辑即可 const script = document.createElement('script') script.className = 'myScriptClass' script.src = chrome.runtime.getURL('/src/dest/payload-min.js') ;(document.head || document.documentElement).appendChild(script) }
对应的background.js中补充消息监听,返回当前帧ID:
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { if (msg.type === 'getFrameId') { sendResponse({frameId: sender.frameId}) } return true })
注意事项
不要尝试把data URI加入WAR的matches列表,Chrome不支持在WAR规则中匹配null源,这类配置会在扩展加载时直接被忽略。
内容的提问来源于stack exchange,提问作者user19487433
相关产品推荐
相关产品推荐

