同源策略和一些跨域方法的记录

286 阅读3分钟

说策略前, 先简单说下一个源的定义.

同源: 如果协议,端口(如果指定了一个)和域名对于两个页面是相同的,则两个页面具有相同的源。

例如下边这个地址: http://www.example.com/dir/other.html

  • 协议是http://
  • 域名是www.example.com
  • 端口是80(默认端口可以省略)

那为什么需要同源策略呢?

先扔个来自MDN的概念.

同源策略 限制 从一个源加载的文档或脚本 与来自另一个源的资源 进行交互。这是一个 用于隔离 潜在恶意文件 的关键的安全机制。

比如你登录微博, 微博服务器建立了个session来记住你, 然后吧session_id返回给客户端存在cookie里, 用来辨识你. 其他网站是不能访问这个cookie的, 不然它就可以获得你得微博的cookie, 然后发送给微博服务器, 伪装成你.

跨源网络访问

但是相应的, 提升安全性的同时也限制了web应用的发展, 所以也不是所有的交互都不能进行.

比如加载cdn上的第三方JS, 图片, 嵌入iframe框等等

请参考MDN上的具体不能交互的分类:

developer.mozilla.org/zh-CN/docs/…

目前来说, 需要解决的是下面3类问题

  1. Cookie,LocalStorage, IndexDB无法读取
  2. DOM无法获得
  3. AJAX请求不能发送

一些跨域的方式.

document.domain

页面可以更改自己的源, 脚本可以将document.domain的值 设置为 当前域 或者 当前域的超级域.

比如说(只是个例子):

http://music.baidu.com/

http://v.baidu.com/

两个地址的二级域名是相同的, 都是'baidu.com', 通过设置 document.domain = 'baidu.com'可以让两个页面共享cookie等信息, 这样当用户登录其中一个网址, 访问baidu.com域下的其他页面就不需要再次登录, 实现了SSO.

跨文档通信api

H5加入了新的API:window.postMessage()方法可以安全地实现跨源通信.

父窗口http://aaa.com向子窗口http://bbb.com:

    var popup = window.open('http://bbb.com', 'title');
    popup.postMessage('Hello World!', 'http://bbb.com');

反过来, 子窗口到父窗口:

    window.opener.postMessage('Nice to see you', 'http://aaa.com');

通过message事件监听:

    window.addEventListener('message', function(e) {
        console.log(e.data);
    },false);

postMessage方法的第一个参数是数据, 没有什么限制,

调用postMessage方法的对象就是发送消息的目标窗口, 由于窗口的地址可以改变, 第二个参数用来指定允许那些接受消息.

协议域名端口完全匹配才能接受到消息.不然会报如下错:

Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('http://www.baidu.com') does not match the recipient window's origin ('https://www.baidu.com').

事件对象MessageEvent的属性:

  1. source: 发送消息的窗口
  2. origin: 发送消息的地址
  3. data: 消息内容
  4. message 属性表示该message 的类型

JSONP

AJAX请求只能发给同源的网址

前边有提到同源策略开放了一些限制, <script>标签相当于浏览器向src发送了一个get请求.

所以, 可以通过添加一个<script>元素,向服务器请求JSON数据,

这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。

也就是通过script标签发送了一个get请求, 并通过将数据包在script中返回给客户端.

例子如下:

//客户端
function addScriptTag(src) {
  var script = document.createElement('script');
  script.setAttribute("type","text/javascript");
  script.src = src;
  document.body.appendChild(script);
}

window.onload = function () {
  addScriptTag('http://www.example.com/some?callback=callbackFunction');
}

function callbackFunction(data) {
  console.log(data);
};

服务器接收到请求后,会将数据放在指定了名字的回调函数的参数位置返回.

返回到客户端的script代码如下:

callbackFunction({
  a: 'a',
b: 'b'
});

CORS(Cross-origin resource sharing)

简单的了解过, 但是没有实际用过, 以后再总结