1. document.domain
在 iframe 中的作用及原理
作用:
通过设置 document.domain
,可以放宽浏览器的同源策略(Same-Origin Policy),允许不同子域(如 a.example.com
和 b.example.com
)的页面通过 JavaScript 直接通信(例如访问彼此的 DOM 或调用函数)。
设置位置:
- 父页面和子页面均需设置:必须同时在父页面和子页面中将
document.domain
设置为相同的值(例如example.com
)。
设置方式:
// 父页面和子页面均需设置
document.domain = "example.com"; // 从子域(如 a.example.com)降级到主域
原理:
- 浏览器会将两个页面的源(Origin)视为同源,前提是它们的
document.domain
相同且为主域的精确匹配。 - 这是浏览器主动支持的行为,属于同源策略的例外规则,但需注意:
- 仅适用于具有相同主域的子域场景(如
a.example.com
→b.example.com
)。 - 现代浏览器已逐步废弃此特性(Chrome 109+ 默认禁用),推荐使用
postMessage
替代。
- 仅适用于具有相同主域的子域场景(如
2. iframe.contentWindow
的作用与限制
作用:
iframe.contentWindow
返回内嵌页面的window
对象,通过它可以访问子页面的全局变量、方法和 DOM。
获取元素:
const iframeWindow = document.querySelector('iframe').contentWindow;
const childElement = iframeWindow.document.querySelector('#elementId');
限制:
- 同源策略:若父子页面不同源,直接访问
contentWindow.document
会抛出安全异常。 - 沙盒模式:如果 iframe 设置了
sandbox
属性且未包含allow-same-origin
,即使同源也会被阻止。
兼容性:
- 所有现代浏览器均支持
contentWindow
,但跨域场景需依赖其他通信方式(如postMessage
)。
3. CSP 策略与 iframe 的集成
配置方式:
- 通过 HTTP 头:使用
Content-Security-Policy
响应头配置。 - 关键指令:
frame-src
:控制允许哪些源作为 iframe 加载(父页面配置)。frame-ancestors
:控制当前页面可以被哪些父页面嵌入(子页面配置)。
配置范围:
- 父页面:需配置
frame-src
指定允许加载的子页面源。 - 子页面:需配置
frame-ancestors
指定允许哪些父页面嵌入自身。 - 独立策略:父子页面的 CSP 策略独立生效,需分别配置。
4. 同域与跨域 iframe 的功能差异及解决方案
同域 iframe
特点:
- 完全访问彼此的 DOM、Cookie、LocalStorage。
- 可直接调用对方函数(如
parent.foo()
)。
解决方案:
直接使用 JavaScript API 操作。
跨域 iframe
功能限制:
- DOM 访问:无法直接读写子页面的 DOM。
- Cookie/Storage:受同源策略隔离。
- 脚本通信:无法直接调用对方函数。
解决方案:
postMessage
通信:// 父页面向子页面发送消息 iframe.contentWindow.postMessage('data', 'https://child.com'); // 子页面监听 window.addEventListener('message', (e) => { if (e.origin === 'https://parent.com') console.log(e.data); });
- CORS 头:
- 子页面设置
Access-Control-Allow-Origin: *
允许跨域资源访问。
- 子页面设置
- 代理服务器:
- 通过后端代理请求绕过浏览器限制。
- 片段标识符(Fragment Identifier):
- 通过 URL Hash 传递数据(仅限单向通信)。
总结
document.domain
是传统跨子域方案,但逐渐被废弃。contentWindow
在同源下功能完整,跨域需结合postMessage
。- CSP 策略 需父子页面协同配置,分别控制加载和嵌入权限。
- 跨域场景 依赖
postMessage
、CORS 和代理等现代方案,兼顾安全与功能。
建议优先使用 postMessage
和 CORS 等标准化的跨域通信机制,避免依赖已废弃的特性(如 document.domain
)。