HTML 内联框架元素 (<iframe>) 表示嵌套的browsing context。它能够将另一个 HTML 页面嵌入到当前页面中。
2. 安全 🔐
2.1 对于使用iframe的页面
iframe属性
iframe标签有些属性可以限制被嵌入页面的能力:
- 沙箱属性
sandbox
- 权限控制
allow
2.2 对于被嵌入的页面
如何检测自己被嵌套了?
方法一:比较 window.self 与 window.top
如果当前页面是最顶层的窗口,那么window.self 和 window.top 指向同一个对象;反之,则说明页面被嵌套了。
if (window.self !== window.parent) {
console.log('当前页面被嵌套在 iframe 中');
// 在这里可以执行跳出嵌套等操作
} else {
console.log('当前页面是顶级窗口,未被嵌套');
}
这个判断逻辑也可以写成 window.top !== window.self或 window !== window.top。
扩展:window.opener / window.parent / window.top 的区别?
window.opener refers to the window that called window.open( ... ) to open the window from which it's called
window.parent refers to the parent of a window in a <frame> or <iframe>
window.top refers to the top-most window from a window nested in one or more layers of <iframe> sub-windows
如何禁止被嵌套?
X-Frame-Options 标头已被 Content Security Policy Level 2 中的 frame-ancestors 指令取代。
https://caniuse.com/?search=X-Frame-Options
frame-ancestors 指令允许指定哪些父级 URL 可以将当前资源嵌入frame中。通过使用 frame-ancestors 这个 CSP 指令,我们可以阻止或允许页面被放置在frame 或 iframe内。
2.3 安全使用window.postMessage()
当父窗口需要与其iFrame通信时(反之亦然),直接的JavaScript访问通常会被同源策略阻止。跨源通信的推荐安全方法是window.postMessage()。但是要安全的使用window.postMessage():
-
始终验证发送者的来源:接收消息时,务必检查event.origin属性,以确保消息来自预期的来源。
-
指定目标来源:发送消息时,提供确切的目标来源(例如,iframeWindow.postMessage('hello', 'https://expected-origin.com');),而不是*。使用*意味着任何窗口都可能接收您的消息,这是一种安全风险。
// 正确:只发送给可信的源
iframe.contentWindow.postMessage('user data', 'https://trusted-domain.com');
- 净化接收到的数据:将通过
postMessage()接收到的任何数据视为不可信输入,并在使用前对其进行净化,以防止XSS。
有了window具柄了为啥还需要targetOrigin参数?
调用postMessgeAPI时,获取到的 otherWindow 引用,比如 iframe.contentWindow 或 window.opener,本质上是一个“指针”。它指向一个窗口对象,但无法保证这个窗口当前加载的页面是预期的(比如用户在iframe里跳转了其他网站)。这个时候就需求postMessage 的 targetOrigin 参数。
targetOrigin 如何提供保护?
targetOrigin 参数要求你明确指定一个源(Origin,包括协议、域名和端口),浏览器在发送消息时会进行校验。
- 校验机制:只有在目标窗口的源与 targetOrigin 完全匹配时,消息才会被发送。如果不匹配,消息会被浏览器直接丢弃,不会发出。
- 精准投递:这个机制确保了消息只能被发送到你指定的、可信的源,而不是任何碰巧占用该窗口引用的网站。
参考
- 由postMessage跨域解决方案引发的双核浏览器兼容性问题的调查与解决方案
- iFrame嵌入安全:Web开发人员的最佳实践
- MDN Content-Security-Policy: frame-ancestors directive
- Google 在您的网站上安全地嵌入内容
1. iframe 基础
2. 安全 🔐
2.1 对于使用
iframe的页面iframe属性iframe标签有些属性可以限制被嵌入页面的能力:sandboxallow2.2 对于被嵌入的页面
如何检测自己被嵌套了?
方法一:比较
window.self与window.top如果当前页面是最顶层的窗口,那么
window.self和window.top指向同一个对象;反之,则说明页面被嵌套了。这个判断逻辑也可以写成
window.top !== window.self或window !== window.top。扩展:
window.opener / window.parent / window.top的区别?如何禁止被嵌套?
1.
X-Frame-Options响应头https://caniuse.com/?search=X-Frame-Options
2.
Content-Security-Policy响应头frame-ancestors指令允许指定哪些父级 URL 可以将当前资源嵌入frame中。通过使用frame-ancestors这个 CSP 指令,我们可以阻止或允许页面被放置在frame或iframe内。2.3 安全使用
window.postMessage()当父窗口需要与其iFrame通信时(反之亦然),直接的JavaScript访问通常会被同源策略阻止。跨源通信的推荐安全方法是
window.postMessage()。但是要安全的使用window.postMessage():始终验证发送者的来源:接收消息时,务必检查
event.origin属性,以确保消息来自预期的来源。指定目标来源:发送消息时,提供确切的目标来源(例如,
iframeWindow.postMessage('hello', 'https://expected-origin.com');),而不是*。使用*意味着任何窗口都可能接收您的消息,这是一种安全风险。postMessage()接收到的任何数据视为不可信输入,并在使用前对其进行净化,以防止XSS。有了window具柄了为啥还需要
targetOrigin参数?调用
postMessgeAPI时,获取到的otherWindow引用,比如iframe.contentWindow或window.opener,本质上是一个“指针”。它指向一个窗口对象,但无法保证这个窗口当前加载的页面是预期的(比如用户在iframe里跳转了其他网站)。这个时候就需求postMessage的targetOrigin参数。targetOrigin如何提供保护?targetOrigin参数要求你明确指定一个源(Origin,包括协议、域名和端口),浏览器在发送消息时会进行校验。参考