iframe 与跨域通信
约 692 字大约 2 分钟
布欧-Lewyon
2026-05-16
首页 › HTML › 进阶话题 › iframe 与跨域通信
嵌入内容已在 B 阶段介绍过基础用法。本节深入 iframe 的安全、通信和高级配置。
sandbox 安全限制详解
sandbox 对嵌入内容施加一系列限制。不同值的组合产生不同的安全级别:
严格隔离(最安全)
<iframe src="https://unknown-site.com" sandbox></iframe>完全不信任的来源,禁止一切:无脚本、无表单、无弹窗、无导航。
选择性开放
<!-- 允许脚本但禁止弹窗和导航 -->
<iframe
src="https://somewhat-trusted.com"
sandbox="allow-scripts allow-same-origin"
></iframe>sandbox 值对照
| 值 | 解除的限制 | 风险 |
|---|---|---|
| (空) | 全部限制 | — |
allow-scripts | 允许执行 JavaScript | ⚠️ 可配合其他限制逃逸 |
allow-same-origin | 视为同源(可访问 Cookies、DOM) | ⚠️ 高危,可能与 allow-scripts 合作用来攻击 |
allow-forms | 允许提交表单 | 低 |
allow-popups | 允许 window.open() / target="_blank" | 中 |
allow-modals | 允许 alert() / confirm() | 低 |
allow-top-navigation | 允许导航父级页面 | ⚠️ 高,可让用户去不安全的页面 |
allow-presentation | 允许进入全屏模式 | 低 |
安全推荐:
<!-- 最低权限原则:只开放必要权限 -->
<iframe src="https://widget.example.com"
sandbox="allow-scripts allow-forms">
</iframe>postMessage 跨域通信
不同源的页面无法直接通过 JS 读写对方的 DOM。postMessage 是最安全的跨文档通信方式。
父 → iframe 发消息
<!-- 父页面 -->
<iframe id="childFrame" src="https://widget.example.com"></iframe>
<script>
const iframe = document.getElementById('childFrame');
iframe.onload = () => {
iframe.contentWindow.postMessage(
{ type: 'SET_THEME', theme: 'dark' },
'https://widget.example.com'
);
};
</script>iframe 中接收
<!-- iframe 内页面 -->
<script>
window.addEventListener('message', (event) => {
// ⭐ 始终验证来源
if (event.origin !== 'https://parent.example.com') return;
const { type, theme } = event.data;
if (type === 'SET_THEME') {
document.body.className = theme;
}
});
</script>iframe → 父发消息
<!-- iframe 内 -->
<script>
window.parent.postMessage(
{ type: 'IFRAME_READY', height: document.body.scrollHeight },
'https://parent.example.com'
);
</script>接收消息的通用模式
window.addEventListener('message', (event) => {
// 1. ⭐ 验证来源(必须)
if (!['https://trusted1.com', 'https://trusted2.com'].includes(event.origin)) {
return;
}
// 2. 验证数据结构
const { type, payload } = event.data || {};
if (!type) return;
// 3. 分发处理
switch (type) {
case 'RESIZE':
document.getElementById('myIframe').style.height = payload.height + 'px';
break;
case 'NAVIGATE':
// ...
break;
}
});自适应高度(自动调整 iframe 高度)
<!-- 父页面 -->
<iframe id="myIframe" src="https://widget.example.com"></iframe>
<script>
window.addEventListener('message', (event) => {
if (event.origin !== 'https://widget.example.com') return;
if (event.data.type === 'RESIZE') {
document.getElementById('myIframe').style.height = event.data.height + 'px';
}
});
</script><!-- iframe 内 -->
<script>
function reportHeight() {
window.parent.postMessage(
{ type: 'RESIZE', height: document.body.scrollHeight },
'https://parent.example.com'
);
}
// 内容变化时报告高度
new ResizeObserver(reportHeight).observe(document.body);
// 或者 MutationObserver 监控 DOM 变化
</script>小结
| 概念 | 要点 |
|---|---|
| sandbox | 限制 iframe 能力,空值最安全 |
| postMessage | 跨域通信,始终验证 event.origin |
| 自适应高度 | postMessage 传递 scrollHeight |
| 安全原则 | 不信来源、最低权限、验证数据结构 |
上一节:Web Workers 与其他 API 下一节:ARIA 无障碍访问
