iframe特性全解读

7,705 阅读7分钟

前言

在平时的开发中,或多或少会用到iframe,大部分时候我们只需要简单的使用iframe标签,设置个宽高即可,很少回去深究iframe的别的特性。比如这种用法:

<iframe src='https://blog.5udou.cn'>

但直到产品经理要求说,iframe嵌入的页面可不可以让主页面的url地址发生变化呀?好吧,一下子懵圈了,我得去查查资料,于是索性就深究深究iframe的一些特性,免得再次尴尬。

下面所有代码都可以在这里找到:github.com/linxiaowu66…

iframe的特性

iframe的特性都是依赖参数配置实现的,现整理如下有用的属性:

属性 解释 备注
allow 可以为iframe指定特性策略
allowfullscreen 是否允许iframe调用requestFullscreen()方法激活全屏模式,这个属性等同于allow属性的这个配置:allow="fullscreen"
allowpaymentrequest 是否允许一个跨域的iframe调用支付请求API
csp 内嵌的资源强制实行同源策略
height iframe的高度,默认150px
importance 标识在iframe属性src指示的资源的下载优先级,有auto/high/low三个等级
name 内嵌的浏览内容的目标名称
referrerpolicy 指示当获取frame的资源的时候携带的referrer,默认是no-referrer-when-downgrade,也就是仅当发生协议降级(如 HTTPS 页面引入 HTTP 资源,从 HTTPS 页面跳到 HTTP 等)时不发送 Referrer 信息。这个规则是现在大部分浏览器默认所采用的;
sandbox 在frame上的内容上运用额外的一下限制,具体哪些字段我们下面详细解释

iframe的allow属性详解

allow属性的使用需要参考特性策略这一小节。特性策略可以允许你控制页面或者iframe可以使用哪些特性。页面控制的话设置在HTTP头部的Feature-Policy的这个字段,iframe的话就是我们要说的这个allow字段。

特性策略的书写规则是:<feature name> <allowlist of origin(s)>

完整的特性名称参考: Policy Controlled Features或者Feature-Policy

而allowlist则有如下规则:

  1. *:表示该特性在该文档下都是允许的,包括所有的嵌套的浏览内容(iframes),而不用管这些内容的源。
  2. self:表示该特性在该文档下都是允许的,并且仅在同源的情况下嵌套的浏览内容(iframes)才可以使用。
  3. src:(iframes的allow属性专用)表示该特性在这个iframe下允许使用,只要加载的文档来源的源和iframe的src属性指定的URL是同源的。
  4. none:表示该特性在顶层以及嵌套的浏览内容下都是被禁用的
  5. <origin(s)>:表示该特性只在一些指定的源下才允许使用,多个源使用空格隔开

今天我们主要讲一下iframe下的allow属性,比如你不允许iframe的页面全屏、不允许调用摄像头之类的行为,可以这么配置:

<iframe allow="camera 'none'; fullscreen 'none'">

比如只允许同源的才可以使用全屏这个特性:

<iframe src="https://example.com..." allow="fullscreen 'src'"></iframe>

比如只允许指定源才可以使用定位功能:

<iframe src="https://google-developers.appspot.com/demos/..." allow="geolocation https://google-developers.appspot.com"></iframe>

iframe的referrerpolicy属性详解

这个属性牵扯到了HTTP的referer策略,我们知道referer的策略是这样的:

  • No Referrer:任何情况下都不发送 Referrer 信息;
  • No Referrer When Downgrade:仅当发生协议降级(如 HTTPS 页面引入 HTTP 资源,从 HTTPS 页面跳到 HTTP 等)时不发送 Referrer 信息。这个规则是现在大部分浏览器默认所采用的;
  • Origin Only:发送只包含 host 部分的 Referrer。启用这个规则,无论是否发生协议降级,无论是本站链接还是站外链接,都会发送 Referrer 信息,但是只包含协议 + host 部分(不包含具体的路径及参数等信息);
  • Origin When Cross-origin:仅在发生跨域访问时发送只包含 host 的 Referrer,同域下还是完整的。它与 Origin Only 的区别是多判断了是否 Cross-origin。需要注意的是协议、域名和端口都一致,才会被浏览器认为是同域;
  • Unsafe URL:无论是否发生协议降级,无论是本站链接还是站外链接,统统都发送 Referrer 信息。正如其名,这是最宽松而最不安全的策略;

比如我们这样配置:

<iframe allow="fullscreen 'none'" referrerpolicy="no-referrer" src='http://127.0.0.1:3000/iframe.html'></iframe>

我们通过抓包可以看到对应的请求是这样的:

iframe的sandbox属性详解

iframe的沙箱模式可以提供一些额外的配置,当你把一个iframe置为沙箱的时候,意味着沙箱内的内容的行为全凭你控制了。

比如你在iframe下这样配置:

<iframe sandbox="" src='http://127.0.0.1:3000/iframe1.html'></iframe>

但是iframe1.html中却有对应的js脚本,那么在控制台下可以看到这样的报错:

Blocked script execution in 'http://127.0.0.1:3000/iframe1.html' because the document's frame is sandboxed and the 'allow-scripts' permission is not set.

所以当你的iframe有脚本的时候,基本上都会配置allow-scripts这个属性。

再比如你的页面会有form标签提交数据的时候,如果没有allow-forms,则会报这种错误:

Blocked form submission to '' because the form's frame is sandboxed and the 'allow-forms' permission is not set.

接下来解释一下各个配置的含义:

属性 解释
allow-forms 允许资源提交表单
allow-modals 允许资源打开模态窗口,比如window.alert()、window.confirm()、window.print()、window.prompt()
allow-orientation-lock 允许资源锁住屏幕方向
allow-pointer-lock 允许资源使用Pointer Lock API
allow-popups 允许弹出窗口(比如window.open(), target="_blank", 或者showModalDialog()),如果这个关键词没有的话,弹出窗口将会静默地打开失败
allow-popups-to-escape-sandbox 允许沙箱文档打开新窗口,而这些新窗口不需要继承沙箱模式。
allow-presentation 允许嵌入者控制是否iframe启用一个展示会话
allow-same-origin 允许将内容作为普通来源对待。如果未使用该关键字,嵌入的内容将被视为一个独立的源。
allow-scripts 允许嵌入的浏览上下文运行脚本(但不能创建弹窗)
allow-top-navigation 允许嵌入的页面的上下文可以导航(加载)内容到顶级的浏览上下文环境(browsing context)。如果未使用该关键字,这个操作将不可用
allow-storage-access-by-user-activation 允许嵌入的页面请求通过Storage Access API使用父页面的存储能力
allow-top-navigation-by-user-activation 允许嵌入的页面的上下文可以导航(加载)内容到顶级的浏览上下文环境(browsing context),但是只能通过用户手势主动调用来初始化

关于沙箱模式的注意点

  • 当被嵌入的文档与主页面同源时,强烈建议不要同时使用allow-scriptsallow-same-origin,否则的话将允许嵌入的文档通过代码删除sandbox属性。虽然你可以这么做,但是这样的话其安全性还不如不用sandbox。
  • 如果攻击者可以将潜在的恶意内容往用户的已沙箱化的iframe中显示,那么沙箱操作的安全性将不再可靠。推荐把这种内容放置到独立的专用域中,减小可能的损失。
  • 沙箱属性(sandbox)在Internet Explorer 9及更早的版本上不被支持

经过上面的解释,想必知道刚开始的那个问题的答案了吧?

Tips

  1. window.frames

frames属性是一个类似数组的对象;因为frames实际上是window对象的别名,frames属性又是可以遍历的,所以它是一个类似数组的对象: window.frames.length === window.length;

frames属性的每一项是框架内的窗口,即框架内的window对象;frames属性的每一项并不是iframe的dom节点!!!若需要获取iframe的dom节点可以通过以下方法: frames[0].frameElement

如果有一个iframe是处于沙箱模式,并且没有设置allow-same-origin,那么虽然你可以访问到window.frames的长度为2,但是当你获取window.frames[1].location的时候会有这样的错误:

DOMException: Blocked a frame with origin "http://127.0.0.1:3000" from accessing a cross-origin frame

配置了allow-same-origin的时候:

没有配置allow-same-origin的时候:

  1. window.top: 顶层窗口,即最上层的窗口

  2. window.parent: 父窗口,如果一个窗口没有父窗口,则它的parent属性为自身的引用;

  3. window.self: 当前窗口,即自身的引用;

参考

  1. iframe