什么是同源策略
- 同源策略限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。
- 一个源的定义:如果协议,端口(如果指定了一个)和域名对于两个页面是相同的,则两个页面具有相同的源。
什么是跨域?跨域有几种实现形式
- 不同源的资源之间的交互就是跨域。
- 实现跨域的几种方式:
1.一些HTML标签和CSS语法能够实现跨源访问:
- <script src="..."></script>标签嵌入跨域脚本。
- <link rel="stylesheet" href="...">标签嵌入CSS。由于CSS的松散的语法规则,CSS的跨域需要一个设置正确的Content-Type消息头。
- <img>嵌入图片。
- <video> 和 <audio>嵌入多媒体资源。
- <object>, <embed> 和 <applet>的插件。
- @font-face引入的字体。一些浏览器允许跨域字体,一些需要同源字体。
- <frame> 和 <iframe>载入的任何资源。站点可以使用X-Frame-Options消息头来阻止这种形式的跨域交互。
2.使用JSONP:
-
JSONP的原理就是通过script标签能够跨域嵌入脚本来实现跨域通信的。示例:
btn.onclick = function () { var js = document.createElement('script') js.src = 'http://localhost:8080/jsonp?callback=renderPage' document.body.appendChild(js) document.body.removeChild(js) } function renderPage(data) { var node = '' for (var key in data) { node += '<li>' + data[key] + '</li>' } ct.innerHTML = node }
3.使用cors:
跨域资源共享( CORS )机制允许 Web 应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。浏览器支持在 API 容器中(例如 XMLHttpRequest 或 Fetch )使用 CORS,以降低跨域 HTTP 请求所带来的风险。
-
CORS与普通的Ajax通信的区别就在于使用CORS需要在目标服务器的HTTP头中设置一个字段,从而声明哪些源站有权限访问哪些资源。如:
服务器端: cors: function (res) { var data = router.news() res.setHeader("Access-Control-Allow-Origin", "*") res.end(JSON.stringify(data)) } 服务端返回的 Access-Control-Allow-Origin: * 表明,该资源可以被任意外域访问。 如果服务端仅允许来自 http://foo.example 的访问,该首部字段的内 容如下:Access-Control-Allow-Origin: http://foo.example
4.降域:
当需要进行跨域的资源位于统一顶级域下时,可以更改它们的源来实现跨域访问。
-
源的更改:页面可能会更改其自己的来源,但有一些限制。脚本可以将 document.domain 的值设置为其当前域或其当前域的超级域。如果将其设置为其当前域的超级域,则较短的域将用于后续原始检查。例如:
假设文档中的一个脚本在 http://store.company.com/dir/other.html 执行以下语句:
document.domain = "company.com";
这条语句执行之后,页面将会成功地通过对 http://company.com/dir/page.html 的同源检测。而同理,company.com 不能设置 document.domain 为 othercompany.com.
浏览器单独保存端口号。任何的赋值操作,包括document.domain = document.domain都会以null值覆盖掉原来的端口号。赋值时必须带上端口号,以确保端口号不会为null。
5.postMessage:
window.postMessage() 方法可以安全地实现跨源通信。当且仅当执行它们的页面位于具有相同的协议,端口号(443为https的默认值),以及主机(模数 Document.domain 由两个页面设置为相同的值)。
-
window.postMessage() 方法被调用时,会在所有页面脚本执行完毕之后向目标窗口派发一个 MessageEvent 消息。 示例:
a页面: var ipt = document.querySelector('#ipt') ipt.addEventListener('input', function () { window.frames[0].postMessage(this.value, '*') }) // 监听其它页面发送来的消息 window.addEventListener('message', function (e) { ipt.value = e.data }) b页面: var ipt = document.querySelector('#ipt') ipt.addEventListener('input', function () { window.parent.postMessage(this.value, '*') }) window.addEventListener('message', function (e) { ipt.value = e.data })