MV3 declarativeNetRequest无法绕过X-Frame-Options DENY问题求助
解决MV3扩展中declarativeNetRequest无法绕过X-Frame-Options DENY的问题
问题根源分析
在多信使扩展场景中,需在example.com(或扩展内部页面)嵌入Twitter、Telegram等站点的iframe,但这些站点设置了X-Frame-Options: DENY及CSP限制,同时Cookie的SameSite属性会阻止跨域会话。MV2中通过chrome.webRequest移除限制头并修改Cookie SameSite可正常解决,但迁移到MV3后两种尝试方案均失效,核心问题如下:
第一种方案的缺陷
- 规则更新逻辑错误:调用
updateSessionRules时同时执行removeRuleIds: [id],但该ID的规则尚未创建,导致整个规则更新操作失败 - Cookie修改方式错误:使用
set操作覆盖整个Set-Cookie值,破坏原有会话数据,与MV2中仅修改SameSite属性的逻辑不符 - 优先级不足:规则优先级设为1,可能被浏览器默认规则覆盖
- CSP处理不完整:仅移除了单独的
frame-ancestors头,未处理包含该指令的Content-Security-Policy头
第二种方案的缺陷
- 限制处理不全面:仅移除
X-Frame-Options,未处理CSP的frame-ancestors限制 - Cookie问题未解决:未修改Cookie的SameSite属性,导致嵌入页面无法正常携带会话Cookie
- 发起域名匹配错误:若嵌入容器是扩展内部页面,
initiatorDomains: ['example.com']不匹配,需改为扩展ID对应的域名
修复方案
1. 权限确认
确保manifest.json中已配置正确权限(现有配置已满足,但需验证):
"permissions": [ "storage", "declarativeNetRequestWithHostAccess", // 其他必要权限... ], "host_permissions": ["<all_urls>"]
2. 修正Session规则实现(替代第一种方案)
修复规则更新逻辑,采用modify操作精准修改Cookie SameSite属性,移除所有iframe限制头:
async function NetRequest() { const targetDomains = ["*://*.twitter.com/*", "*://*.telegram.org/*"]; const tabId = await getObjectFromLocalStorage('tabId'); let tabMultiId = JSON.parse(await getObjectFromLocalStorage('tabMultiId')) || []; tabMultiId.push(tabId); // 批量生成规则 const newRules = targetDomains.map((domain, idx) => ({ id: idx + 1, priority: 1000, // 提高优先级确保规则优先生效 action: { type: "modifyHeaders", responseHeaders: [ // 移除iframe限制相关头 { header: "X-Frame-Options", operation: "remove" }, { header: "Content-Security-Policy", operation: "remove" }, { header: "X-Content-Security-Policy", operation: "remove" }, { header: "Strict-Transport-Security", operation: "remove" }, // 修改SameSite=Strict/Lax为SameSite=None { header: "Set-Cookie", operation: "modify", regexReplace: "(SameSite=Strict|SameSite=Lax)", replaceWith: "SameSite=None" }, // 为仅含Secure的Cookie添加SameSite=None { header: "Set-Cookie", operation: "modify", regexReplace: "(; Secure)(?!.*SameSite=None)", replaceWith: "; SameSite=None; Secure" } ] }, condition: { urlFilter: domain, resourceTypes: ["sub_frame", "main_frame", "xmlhttprequest"], // 仅包含必要资源类型 tabIds: tabMultiId } })); // 先移除旧规则,再添加新规则 const oldRuleIds = newRules.map(r => r.id); await chrome.declarativeNetRequest.updateSessionRules({ removeRuleIds: oldRuleIds, addRules: newRules }); } async function launchWindow(newURL, windowDimensions, urlWindow, isIncognitoWindow, windowType) { chrome.windows.create({ url: newURL, type: windowType, incognito: isIncognitoWindow, width: windowDimensions.width, height: windowDimensions.height, left: windowDimensions.left, top: windowDimensions.top }, async (chromeWindow) => { // 修正逻辑错误:原||会导致条件永远为true if (urlWindow !== "install" && urlWindow !== "update") { await chrome.storage.local.set({ extensionWindowId: chromeWindow.id, tabId: chromeWindow.tabs[0].id }); await NetRequest(); } }); }
3. 修复固定域名嵌入方案(第二种方案优化)
若嵌入容器是example.com外部页面,调整规则覆盖所有限制并处理Cookie:
const iframeHosts = ['twitter.com', 'telegram.org']; const RULE_ID = 1; const embedRule = { id: RULE_ID, priority: 1000, condition: { initiatorDomains: ['example.com'], requestDomains: iframeHosts, resourceTypes: ['sub_frame', 'main_frame'], }, action: { type: 'modifyHeaders', responseHeaders: [ { header: 'X-Frame-Options', operation: 'remove' }, { header: 'Content-Security-Policy', operation: 'remove' }, // 修改Cookie SameSite属性 { header: 'Set-Cookie', operation: 'modify', regexReplace: "(SameSite=Strict|SameSite=Lax)", replaceWith: "SameSite=None" }, { header: 'Set-Cookie', operation: 'modify', regexReplace: "(; Secure)(?!.*SameSite=None)", replaceWith: "; SameSite=None; Secure" } ], }, }; // 更新动态规则 chrome.declarativeNetRequest.updateDynamicRules({ removeRuleIds: [RULE_ID], addRules: [embedRule], });
关键注意事项
- 优先级设置:必须将规则优先级设为较高值(如1000),确保优先于浏览器或其他扩展的规则
- Cookie修改方式:务必使用
modify+regexReplace操作,避免用set覆盖原有Cookie数据 - 资源类型筛选:仅包含必要的resourceTypes,减少不必要的性能开销
- 扩展页面适配:若嵌入容器是扩展内部页面,需将
initiatorDomains改为["chrome-extension://<你的扩展ID>"],或通过requestInitiator的urlFilter匹配扩展URL
内容的提问来源于stack exchange,提问作者user1327579
相关产品推荐
相关产品推荐

