Manifest V3下如何修改重定向请求Cookie并实现Cookie沙箱?
针对302重定向场景下异步更新规则失效的问题,以下是两种可行的实现方案:
方案一:预生成标签专属的declarativeNetRequest规则
核心思路是提前为每个标签页创建Cookie隔离规则,避免请求时异步更新规则的竞态问题——302重定向属于同标签请求,会自动匹配预先生成的规则。
步骤1:标签初始化时生成隔离标识
监听tabs.onCreated事件,为每个新标签初始化专属Cookie存储,并预创建匹配该标签的网络规则:chrome.tabs.onCreated.addListener(async (tab) => { // 初始化标签专属Cookie存储 await chrome.storage.session.set({ [`tab_${tab.id}_cookies`]: {} }); // 预创建该标签的Cookie替换规则 await chrome.declarativeNetRequest.updateSessionRules({ addRules: [ // 拦截请求,替换Cookie头为标签专属值 { id: tab.id + 1000, priority: 1, action: { type: "modifyHeaders", requestHeaders: [ { header: "cookie", operation: "set", value: await getTabCookieString(tab.id) } ] }, condition: { tabIds: [tab.id], urlFilter: "*://*/*", // 可缩小到目标站点 resourceTypes: ["main_frame", "sub_frame", "xmlhttprequest", "script"] } }, // 拦截响应,阻止浏览器写入全局Cookie { id: tab.id + 2000, priority: 1, action: { type: "modifyHeaders", responseHeaders: [ { header: "set-cookie", operation: "remove" } ] }, condition: { tabIds: [tab.id], urlFilter: "*://*/*", resourceTypes: ["main_frame", "sub_frame", "xmlhttprequest", "script"] } } ] }); });步骤2:处理响应中的Set-Cookie
用非阻塞的webRequest.onHeadersReceived监听响应,解析Set-Cookie并存入对应标签的存储:chrome.webRequest.onHeadersReceived.addListener( async (details) => { const setCookieHeaders = details.responseHeaders?.filter(h => h.name.toLowerCase() === "set-cookie"); if (!setCookieHeaders || !details.tabId) return; const tabCookieKey = `tab_${details.tabId}_cookies`; const stored = await chrome.storage.session.get(tabCookieKey); const tabCookies = stored[tabCookieKey] || {}; setCookieHeaders.forEach(header => { const [keyValue] = header.value.split(";"); const [key, value] = keyValue.split("="); tabCookies[key] = value; }); await chrome.storage.session.set({ [tabCookieKey]: tabCookies }); // 更新对应标签的请求规则 await updateTabCookieRule(details.tabId); }, { urls: ["*://*/*"] }, ["responseHeaders"] );步骤3:动态更新请求Cookie规则
当标签Cookie变化时,更新对应的会话规则:async function getTabCookieString(tabId) { const tabCookieKey = `tab_${tabId}_cookies`; const stored = await chrome.storage.session.get(tabCookieKey); return Object.entries(stored[tabCookieKey] || {}) .map(([k, v]) => `${k}=${v}`) .join("; "); } async function updateTabCookieRule(tabId) { const cookieStr = await getTabCookieString(tabId); await chrome.declarativeNetRequest.updateSessionRules({ removeRuleIds: [tabId + 1000], addRules: [ { id: tabId + 1000, priority: 1, action: { type: "modifyHeaders", requestHeaders: [{ header: "cookie", operation: "set", value: cookieStr }] }, condition: { tabIds: [tabId], urlFilter: "*://*/*", resourceTypes: ["main_frame", "sub_frame", "xmlhttprequest", "script"] } } ] }); }
方案二:内容脚本劫持页面Cookie操作
绕开网络层面的竞态,直接在页面上下文重写document.cookie,让页面读写的是扩展存储的标签专属Cookie,同时配合网络拦截确保一致性。
步骤1:配置内容脚本(manifest.json)
"content_scripts": [ { "matches": ["*://*/*"], "js": ["content.js"], "runAt": "document_start", // 页面加载前注入,确保优先执行 "all_frames": true } ]步骤2:内容脚本重写document.cookie
// content.js (function() { chrome.runtime.sendMessage({ action: "getTabId" }, async (tabId) => { const tabCookieKey = `tab_${tabId}_cookies`; let stored = await chrome.storage.session.get(tabCookieKey); let tabCookies = stored[tabCookieKey] || {}; // 重写Cookie读写逻辑 Object.defineProperty(document, "cookie", { get: function() { return Object.entries(tabCookies) .map(([k, v]) => `${k}=${v}`) .join("; "); }, set: function(value) { const [keyValue] = value.split(";"); const [key, val] = keyValue.split("="); tabCookies[key] = val; chrome.storage.session.set({ [tabCookieKey]: tabCookies }); // 通知后台更新网络规则 chrome.runtime.sendMessage({ action: "updateCookieRule", tabId }); return value; }, configurable: true }); }); })();步骤3:后台配合处理网络请求
同方案一的网络拦截逻辑,确保请求头携带标签专属Cookie,响应的Set-Cookie不写入全局存储。
关键注意事项
- 用
chrome.storage.session存储标签专属Cookie,标签关闭后自动清除,避免内存泄漏。 - 缩小
declarativeNetRequest的urlFilter范围,只匹配目标站点,提升性能。 - 需处理Cookie的domain、path、expires等属性,确保隔离规则符合Cookie规范。
- 覆盖所有相关资源类型(如xmlhttprequest、script),避免遗漏跨域请求的Cookie处理。
内容的提问来源于stack exchange,提问作者Daniel Kleinstein
相关产品推荐
相关产品推荐

