同源政策

2019-08-25  本文已影响0人  Camilia_yang

"同源政策"是浏览器安全的基石。

含义

它最初的含义是指,A网页设置的 Cookie,B网页不能打开,除非这两个网页"同源"。

“同源”的概念

"同源"指的是"三个相同":协议相同 、域名相同、端口相同

http://www.example.com/dir/page.html这个网址,协议是http://,域名是www.example.com,端口是80(默认端口可以省略)。
它与http://example.com/dir/other.html不同源,其域名不同(只是一级域名相同)。

同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。如果 Cookie 包含隐私(比如存款总额),这些信息就会泄漏。更可怕的是,Cookie 往往用来保存用户的登录状态,如果用户没有退出登录,其他网站就可以冒充用户,为所欲为。因为浏览器同时还规定,提交表单不受同源政策的限制。

限制范围

如果非同源,共有三种行为受到限制。

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

同源政策的规避

Cookie

服务器在设置Cookie的时候,指定Cookie的所属域名为一级域名,比如.example.com。
Set-Cookie: key=value; domain=.example.com; path=/
这样的话,二级域名和三级域名不用做任何设置,都可以读取这个Cookie。
提醒:
前端最好不要随意去设置cookie,因为cookie信息量太大会影响到请求和响应的速度,所以最好统一由后端去设置。

iframe

如果两个网页不同源,就无法拿到对方的DOM。典型的例子是iframe窗口和window.open方法打开的窗口,它们与父窗口无法通信。
父窗口运行下面的命令,如果iframe窗口不是同源,就会报错。

document.getElementById("myIFrame").contentWindow.document`
// Uncaught DOMException: Blocked a frame from accessing a cross-origin frame.

反之亦然,子窗口获取主窗口的DOM也会报错。

window.parent.document.body
// 报错

对于完全不同源的网站,目前有三种方法,可以解决跨域窗口的通信问题。

  • 片段识别符(fragment identifier)
  • window.name
  • 跨文档通信API(Cross-document messaging)

AJAX

同源政策规定,AJAX请求只能发给同源的网址,否则就报错。
除了架设服务器代理,有三种方法规避这个限制。

  • JSONP
  • WebSocket
  • CORS

JSONP
JSONP是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,老式浏览器全部支持,服务器改造非常小。

它的基本思想是,网页通过添加一个<script>元素,向服务器请求JSON数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。

首先,网页动态插入<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://example.com/ip?callback=foo');
}

function foo(data) {
  console.log('Your public IP address is: ' + data.ip);
};

上面代码通过动态添加<script>元素,向服务器example.com发出请求。注意,该请求的查询字符串有一个callback参数,用来指定回调函数的名字,这对于JSONP是必需的。

服务器收到这个请求以后,会将数据放在回调函数的参数位置返回。

foo({
  "ip": "8.8.8.8"
});

由于<script>元素请求的脚本,直接作为代码运行。这时,只要浏览器定义了foo函数,该函数就会立即调用。作为参数的JSON数据被视为JavaScript对象,而不是字符串,因此避免了使用JSON.parse的步骤。

WebSocket
WebSocket是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。
下面是一个例子,浏览器发出的WebSocket请求的头信息


GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

上面代码中,有一个字段是Origin,表示该请求的请求源(origin),即发自哪个域名。服务器可以根据这个字段,判断是否许可本次通信。如果该域名在白名单内,服务器就会做出回应。

CORS
什么是 CORS:Cross-Origin Resource Sharing(跨域资源共享)
比如,a.com的前端向b.com的服务器发请求
request.open('GET', 'http://b.com:8002/ada')
会报错了,因为不是同源,响应完成却得不到任何内容
解决方法,在Node代码中加入一句

//允许 http://ada.com:8001 访问我
response.setHeader('Access-Control-Allow-Origin','http://ada.com:8001')

这就是用CORS实现AJAX跨域的过程

参考资料:
http://www.ruanyifeng.com/blog/2016/04/cors.html

上一篇下一篇

猜你喜欢

热点阅读