用趣味学习法理解iframe的跨域通信
一、前言
之前的需求迭代,遇到一个iframe跨域通信的问题,域名B的一个接口请求里的字段用到里域名A下的账户id,原本的代码是直接用sessionStorage.getItem(info)的方式从域名A的缓存中获取用户信息,结果没有拿到。
于是,我脑海里回忆iframe相关的知识点,想到不同域名下的信息是无法直接获取的。没错,这个本应该熟悉的iframe基础知识点,我靠几分钟的回忆才想起来。改完需求之后,我想我是时候重拾一下iframe的相关知识了。
以下关于iframe的介绍主要来自MDN。
二、基础信息
<iframe>,它是HTML内联框架元素,表示嵌套的browsing context。它能够将另一个HTML页面嵌入到当前页面中。
每个嵌入的浏览上下文(embedded browsing context)都有自己的会话历史记录(session history)和DOM树。包含嵌入内容的浏览上下文称为父级浏览上下文。*浏览上下文(没有父级)通常是由 Window 对象表示的浏览器窗口。
三、属性
3.1 allow
用户为<iframe>指定特征策略。
3.1.1 特征策略
简单介绍一下特征策略,特征策略允许web开发者在浏览器中选择启用、禁用和修改确切特征和 API 的行为.比如内容安全策略,但是它控制的是浏览器的特征非安全行为。allow是iframe特有的特征策略,可以控制iframe使用哪些特征。
特征策略的语法
<allowlist>
*: 本特性默认在最上层和包含的内容中(iframes)允许。
'self': 本特性默认在最上层允许,而包含的内容中(iframes)使用源地址相同设定。也就是说本特性在iframe中不允许跨域访问。
'none': 本特性默认在最上层和包含的内容中(iframes)都禁止。
'src': (只在iframe中允许) 只要在src 中的URL和加载iframe用的URL相同,则本特性在iframe中允许。
其中*或'none'只允许单独使用,而'self'和'src'可以与多个源地址一起使用。
3.1.2 语法
禁止全屏模式
可以设置fullscreen的特征策略为'none'。
<iframe allow="fullscreen 'none'">
支持多个特征策略
禁止全屏模式和禁止调起支付接口,多个用分号隔开。
<iframe allow="fullscreen 'none'; payment 'none'">
3.2 csp
对嵌入的资源配置内容安全策略。
3.2.1 内容安全策略( CSP )
内容安全策略 (CSP) 是一个额外的安全层,用于检测并削弱某些特定类型的攻击,包括跨站脚本 (XSS (en-US)) 和数据注入攻击等。无论是数据盗取、网站内容污染还是散发恶意软件,这些攻击都是主要的手段。
设置内容安全策略
比如一个引入的css文件,如果我们设置了如下策略,该策略禁止任何资源的加载,除了来自cdn.example.com的样式表。
head中设置安全策略并引入外部的css文件:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'cdn.example.com'; " /> <title>iframe-child</title> <link rel="stylesheet" href="./style.css" /> </head> <body> </body> </html>
这个时候如果在浏览器打开页面,打开开发者工具就能看到报错:
Refused to load the stylesheet 'file:///Users/Desktop/weblearn/iframe/style.css' because it violates the following Content Security Policy directive: "style-src 'cdn.example.com'". Note that 'style-src-elem' was not explicitly set, so 'style-src' is used as a fallback.
这表示样式表仅允许加载自cdn.example.com,然而该页面企图从自己的源加载。
3.3 height
以CSS像素格式HTML5,或像素格式HTML 4.01,或百分比格式指定frame的高度。默认值为150。
3.4 importance
表示 <iframe> 的 src 属性指定的资源的加载优先级。允许的值有:
auto (default):不指定优先级。浏览器根据自身情况决定资源的加载顺序
high:资源的加载优先级较高
low:资源的加载优先级较低
3.4 name
用于定位嵌入的浏览上下文的名称。该名称可以用作 <a> 标签与 <form> 标签的 target 属性值,也可以用作 <input> 标签和 <button> 标签的 formtarget 属性值,还可以用作 window.open() 方法的 windowName 参数值。
用作 <a> 标签的 target 属性值:
<iframe name="myIframe" src="http://www.w3cschool.cc" width="500" height="200"></iframe> <a href="https://juejin.cn/" target="myIframe">掘金</a>
点击掘金按钮前展示:
点击掘金按钮后展示:
在iframe窗口中打开页面
使用window.open()打开窗口,该方法的第二个参数可以指定窗口名称,我们通过window.name可以拿到iframe的name,赋值到window.open()中。
父页面:
<iframe name="myIframe" src="./child.html" width="500" height="200"></iframe>
iframe页面:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>iframe-child</title> </head> <body> <div> <input type="button" id="open" value="打开弹窗" /> </div> <script> window.onload = function () { var div = document.querySelector('div'); document.querySelector('#open').onclick = function () { window.open('https://juejin.cn/', window.name); }; }; </script> </body> </html>
可以在当前iframe窗口中打开掘金的页面:
3.5 referrerpolicy
表示在获取 iframe 资源时如何发送 referrer 首部:
no-referrer: 不发送 Referer 首部。
no-referrer-when-downgrade (default): 向不受 TLS (HTTPS) 保护的 origin 发送请求时,不发送 Referer 首部。
origin: referrer 首部中仅包含来源页面的源。换言之,仅包含来源页面的 scheme, host, 以及 port (en-US)。
origin-when-cross-origin: 发起跨域请求时,仅在 referrer 中包含来源页面的源。发起同源请求时,仍然会在 referrer 中包含来源页面在服务器上的路径信息。
same-origin: 对于 same origin (同源)请求,发送 referrer 首部,否则不发送。
strict-origin: 仅当被请求页面和来源页面具有相同的协议安全等级时才发送 referrer 首部(比如从采用 HTTPS 协议的页面请求另一个采用 HTTPS 协议的页面)。如果被请求页面的协议安全等级较低,则不会发送 referrer 首部(比如从采用 HTTPS 协议的页面请求采用 HTTP 协议的页面)。
strict-origin-when-cross-origin: 当发起同源请求时,在 referrer 首部中包含完整的 URL。当被请求页面与来源页面不同源但是有相同协议安全等级时(比如 HTTPS→HTTPS),在 referrer 首部中仅包含来源页面的源。当被请求页面的协议安全等级较低时(比如 HTTPS→HTTP),不发送 referrer 首部。
unsafe-url: 始终在 referrer 首部中包含源以及路径 (但不包括 fragment,密码,或用户名)。这个值是不安全的, 因为这样做会暴露受 TLS 保护的资源的源和路径信息。
不添加referrerpolicy
<iframe name="myIframe" src="https://juejin.cn/" width="500" height="200" />
可以在请求中看到referrer的来源:
no-referrer
将referrerpolicy的值设置为no-referrer
<iframe name="myIframe" src="https://juejin.cn/" width="500" height="200" referrerpolicy="no-referrer" />
我们在请求中会看不到referrer的来源:
origin
将referrerpolicy的值设置为origin
<iframe name="myIframe" src="https://juejin.cn/" width="500" height="200" referrerpolicy="origin" />
可以在请求中看到referrer的来源:
origin-when-cross-origin
将referrerpolicy的值设置为origin-when-cross-origin
<iframe name="myIframe" src="https://juejin.cn/" width="500" height="200" referrerpolicy="origin-when-cross-origin" />
非同源请求的referrer的来源:
same-origin
将referrerpolicy的值设置为same-origin