
本文介绍一种基于 Object.defineProperty 拦截 document.cookie 写入操作并结合调用栈分析的技术方案,可在浏览器环境中可靠识别外部脚本(如来自 domain B)在当前页面(domain A)设置 Cookie 的原始来源域。
本文介绍一种基于 `object.defineproperty` 拦截 `document.cookie` 写入操作并结合调用栈分析的技术方案,可在浏览器环境中可靠识别外部脚本(如来自 domain b)在当前页面(domain a)设置 cookie 的原始来源域。
在 Web 安全与调试实践中,常遇到跨域脚本(如嵌入的第三方 SDK、广告或分析脚本)在当前站点(domain A)静默设置 Cookie 的场景。由于同源策略限制,JavaScript 无法直接读取 document.cookie 的元信息(如 Domain 属性的设置者、HTTP 响应头中的 Set-Cookie 发起源),也无法通过标准 API 获取 Cookie 的“创建者域”。但我们可以借助 JavaScript 运行时的执行上下文特性,主动监控 cookie 设置行为本身,从而逆向推断其来源。
核心思路是:重定义 document.cookie 的 setter,捕获每次赋值操作,并利用错误堆栈(stack trace)定位触发该操作的脚本 URL。现代浏览器(Chrome、Firefox、Edge)在 Error.stack 中会包含调用 document.cookie = ... 的脚本路径,且堆栈底部(最后一行)通常指向实际执行写入的外部脚本(如 http://domain.b/script.js)。
以下为可直接部署的调试脚本:
<script type="text/javascript">
function monitorCookieOrigin() {
// 仅在开发/调试阶段启用,避免生产环境性能损耗
if (typeof document === 'undefined') return;
const originalDescriptor = Object.getOwnPropertyDescriptor(Document.prototype, 'cookie');
if (!originalDescriptor || !originalDescriptor.set) return;
Object.defineProperty(document, 'cookie', {
set: function(value) {
// 构造错误对象以捕获当前调用栈
const err = new Error();
const stackLines = (err.stack || '').split('\n');
// 提取最可能的发起脚本行(通常为倒数第二或第三行,跳过 native / set 行)
let initiator = 'unknown';
for (let i = Math.min(3, stackLines.length - 1); i >= 0; i--) {
const line = stackLines[i].trim();
if (line.includes('@') && (line.includes('http://') || line.includes('https://'))) {
initiator = line.split('@')[1].split(':')[0];
break;
}
}
console.info('[Cookie Origin Monitor]', {
value: value.substring(0, 100), // 防止过长日志
initiator: initiator,
timestamp: new Date().toISOString()
});
},
get: originalDescriptor.get
});
}
// 立即启用监控
monitorCookieOrigin();
</script>✅ 使用效果示例:
当 domain.b/script.js 执行 document.cookie = "session=abc123; domain=domain.a" 时,控制台将输出类似:
[Cookie Origin Monitor] {
"value": "session=abc123; domain=domain.a",
"initiator": "http://domain.b/script.js",
"timestamp": "2024-06-15T08:22:34.123Z"
}⚠️ 重要注意事项:
立即学习“Java免费学习笔记(深入)”;
- 仅适用于 JavaScript 设置的 Cookie:该方法无法捕获通过 HTTP 响应头 Set-Cookie 直接下发的 Cookie(例如后端重定向或 iframe 加载触发的 Set-Cookie),因其不经过 document.cookie setter。
- 浏览器兼容性:Chrome、Firefox、Edge 支持良好;Safari 对 Error.stack 格式支持较弱,建议配合 console.trace() 做降级处理。
- 性能与安全:重定义原生属性存在微小性能开销,且不应在生产环境长期启用;若需自动化审计,建议封装为 DevTools 扩展或 Puppeteer 脚本。
- Domain 属性误导风险:注意 document.cookie setter 中显式指定的 Domain= 参数(如 Domain=domain.a)仅代表 Cookie 作用域,并非创建者域——真正的创建者始终是执行该 JS 的脚本所在源(origin)。
总结而言,虽然浏览器未提供“Cookie 来源域”的标准 API,但通过运行时拦截 + 堆栈分析这一轻量级调试技术,开发者可精准、实时地识别跨域脚本对 Cookie 的写入行为,为安全审计、合规检查及第三方依赖治理提供关键依据。










