原文章出处
作者:Eason_Wong 链接:www.jianshu.com/p/7ec986aa2… 来源:简书
iframe基本概念
<iframe src="demo.html" width="500" height="300" name="demo" scrolling="auto" sandbox="allow-same-origin"></iframe>
iframe属性:
- src iframe页面地址,有同域跨域之分
- height iframe高度
- width iframe宽度
- name iframe命名,可通过window.frames[xxx]被调用
- scrolling iframe滚动模式
- sandbox html5新特性,用于限制iframe的功能
使用iframe的正确姿势
通过contentWindow和contentDocument两个API获取iframe的window对象和document对象。
let iframe = document.getElementById('demo');
let iwindow = iframe.contentWindow; // 获取iframe的window对象
let idocument = iframe.contentDocument; // 获取iframe的document对象
iframe使用父级内容的正确姿势
通过window.self,window.parent,window.top这三个属性分别获取自身window对象,父级window对象,顶级window对象。
index.html
|
-- iframe1.html
|
-- iframe2.html
iframe2.self === iframe2
iframe2.parent === iframe1
iframe2.top === window
iframe同域/跨域
一般会使用iframe来进行父子页面的通信,然鹅父子页面是否同域决定了它们之间能否进行通信。
js遵循同源策略,即同协议,同域名,同端口号,否则都算跨域。
同源策略 是由Netscape提出的一个著名的安全策略,现在所有支持JavaScript 的浏览器都会使用这个策略。实际上,这种策略只是一个规范,并不是强制要求,各大厂商的浏览器只是针对同源策略的一种实现。它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。
跨域 简单的来说,指的是两个资源非同源。出于安全方面的考虑,页面中的JavaScript在请求非同源的资源时就会出 跨域问题 ——即跨域请求,这时,由于同源策略,我们的请求会被浏览器禁止。也就出现了 我们常说的 跨域 问题。
iframe跨域通讯之document.domain
对于主域相同子域不同的两个页面,我们可以通过document.domain + iframe来解决跨域通信问题。
网页a(www.easonwong.com)和网页b(script.easonwong.com),两者都设置document.domain = 'easonwong.com'(这样浏览器就会认为它们处于同一个域下),然后网页a再创建iframe上网页b,就可以进行通信。
网页a
document.domain = 'easonwong.com';
var ifr = document.createElement('iframe');
ifr.src = 'http://script.easonwong.com';
ifr.style.display = 'none';
document.body.appendChild(ifr);
ifr.onload = function(){
let doc = ifr.contentDocument || ifr.contentWindow.document;
// 在这里操纵b.html
};
网页b
document.domain = 'easonwong.com';
iframes跨域通讯之postMessage
postMessage是html5的新特性,兼容性 IE8以上, window.postMessage可以安全地实现跨源通信。
举例: http://127.0.0.1:5500/index.html作为父级 http://127.0.0.1:3000/iframe1.html作为iframe页
http://127.0.0.1:5500/index.html
// 发送消息
let ifr = document.createElement('iframe');
ifr.src = '//127.0.0.1:3000/iframe1.html';
ifr.style.display = 'none';
document.body.appendChild(ifr);
ifr.onload = function () {
ifr.contentWindow.postMessage("message by postmessage: hello, I'm a", 'http://127.0.0.1:3000');
}
// 接收消息
window.addEventListener('message', receiver, false);
function receiver(e) {
if (e.origin == 'http://127.0.0.1:3000') {
console.log(e.data);
}
}
http://127.0.0.1:3000/iframe1.html
// 监听message事件,做origin校验,并回应原网页
window.addEventListener('message', receiver, false);
function receiver(e) {
if (e.origin == 'http://127.0.0.1:5500') {
log(e.data)
e.source.postMessage('copy that! I\'m b!', e.origin);
}
}
iframe实现JSBridge
在移动端Hybrid混合模式中经常用到JSBridge进行JS和Native之间的通信,其中我们可以通过iframe的方式实现JS调用Native的方法。
以上提到的方法就是URL SCHEME拦截。
URL SCHEME是一种类似于url的链接,是为了方便app直接互相调用设计的,形式和普通的 url 近似,主要区别是 protocol 和 host 一般是自定义的。
例如: easonwong://hh/url?name=easonwong,其中protocol是easonwong,host则是hh。
我们通过创建一个iframe(src设为我们自定义的URL SCHEME)来发送请求,然后Native那边可以拦截到请求并获取其中带有的参数,即可进行后续的操作。
iframe其他用途
- 用iframe进行异步请求
- 引用/展示第三方内容
- 需要独立样式和带有交互的内容,例如幻灯片
- sandbox沙箱隔离
- 历史记录管理
防嵌套页面操作
在前端领域,我们可以通过window.top来防止我们页面被嵌套。
if(window != window.top){
window.top.location.href = myURL;
}
或者通过window.location.host来检测是否跨域了
if (top.location.host != window.location.host) {
  top.location.href = window.location.href;
}
而后端也可以做对应的防范措施,通过设置X-Frame-Options响应头来确保自己网站的内容没有被嵌到别人的网站中去,也从而避免了点击劫持 (clickjacking) 的攻击。
CSP
内容安全策略(CSP)用于检测和减轻用于 Web 站点的特定类型的攻击,例如 XSS 和数据注入等。
通过CSP配置sandbox和child-src可以设置iframe的有效地址,它限制适iframe的行为,包括阻止弹出窗口,防止插件和脚本的执行,而且可以执行一个同源策略。
可以在html头部中加上标签
<meta http-equiv="Content-Security-Policy" content="child-src 'unsafe-inline' 'unsafe-eval' www.easonwong.com">