same-origin policy 和 cross-origin resource sharing(CORS)

 同源策略和cors的信息量太多。网络上很少有全面总结的文章。学习同源策略最大的收获是,之前忽略了浏览器在安全中的重要性,总以为安全主要靠服务端。浏览器(协议规范)和服务端都非常重要。

 

host和domain

host

https://url.spec.whatwg.org/#concept-host

domain

https://url.spec.whatwg.org/#concept-domain

 根据以上的定义,domain是“域名“,比如baidu.com,host可以是domain,或者ip地址,或者opaque host。

显然对于大部分开发情况,domain等于host,就是一个域名

 

opaque host

资料甚少,参考https://github.com/w3c/wpub/issues/321

比如file://这种host就是opaque host的一种,与常见的domain不一样。不太需要关注。

 

origin的定义

源的定义:

https://html.spec.whatwg.org/multipage/origin.html#concept-origin

基本上可以理解为

协议(http/https/...) + host(domain) + port

只能3者都一样,才叫同源。

x.baidu.com 与 y.baidu.com  就不是同源。

 

同源策略

同源策略是互联网安全的基石。一个浏览器tab打开了源A,另一个tab打开了源B,源A的tab不能访问到源B tab的数据,包括cookie数据和dom数据。浏览器提供了这样的安全保障。

但是HTML除了cookie和dom,还有:

  • JavaScript
  • img,vedio
  • css
  • 跨域请求(源A向源B请求数据)
  • document.domain API可以修改当前页面的domain

违反了同源策略的访问,统称为跨域访问

详细的定义可以查阅:

https://code.google.com/archive/p/browsersec/wikis/Part2.wiki

https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy

 

跨域访问

按照MDN的说法:

same-origin policy 和 cross-origin resource sharing(CORS)_第1张图片

  • 跨域写请求一般是被允许的(比如form提交)(这里的“被允许”只是浏览器不会主动阻止这次请求)
  • 跨域embed一般是被允许的(同上)
  • 跨域读请求一般是不允许的(浏览器和服务端都有安全措施)。于是有一些人鸡贼的想用embed来做跨域的读。

 

CORS

cross-origin resource sharing. 通过JS脚本来发起请求(AJAX或者fetch API, 与AJAX大同小异)

在互联网上,有的服务端愿意开放自己的数据,有的不愿意

CORS规范了不同情况下浏览器和服务端的行为。

详细说明:

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

 

CORS与origin请求头

在CORS的说明中,“简单”请求不会触发CORS预检测机制。

要求“简单”请求的请求头只能有以下类型

same-origin policy 和 cross-origin resource sharing(CORS)_第2张图片

 

 但是浏览器发现一个请求是跨域请求时,一定会在请求中加入头部

origin

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin

服务端可以根据这个头部做出相应处理。没法用脚本阻止浏览器添加此头部。

 

CORS与预检测请求

不是“简单”请求的脚本跨域请求,都是预检测请求。浏览器会执行预检测机制。

预检测机制会先用option method请求服务器,看服务端是否支持当前origin的跨域请求.

不管是简单请求还是预检测请求,涉及到的http头部常见的有:

Access-Control-Allow-Origin
允许跨域访问的域
Access-Control-Max-Age
在多长的时间内,跨域访问不再需要预检测机制
Access-Control-Allow-Headers
允许跨域时含有这些请求header

 

不管是简单跨域请求还是预检测跨域请求,都会发送http请求到服务端。

收到服务端返回后,如果:

  1. 返回头没有任何跨域相关的header,视为不允许跨域
  2. 返回头中有跨域相关的header,且允许此次跨域,一切正常。
  3. 返回头中有跨域相关的header,且不予许此次跨域,浏览器报错

即使是被服务端的返回header拒绝跨域请求,通过fiddler抓包,可以看到整个http请求是已经完成的,数据body也都传输到了浏览器。

 

Chrome浏览器的“Provisional headers are shown”

如下图,一些请求在chrome调试器中看到请求头被标上了"provisional headers are shown", 直译就是“显示的是临时的请求头”

出现这个提示最常见的情况下数据有缓存,不过也有其他情况:

  1. 浏览器装了广告拦截插件,广告请求被拦截了
  2. 一个请求还没完成被用户取消了
  3. 服务端长时间没反应,超时了

还要一种情况与跨域有关。在跨域预处理中,会先发送options请求,但是如果服务端不能正确处理options请求,会导致请求超时,出现这个警告。

通过chrome自带插件可以查看chrome的log,看看发生了什么。

chrome://net-export/

same-origin policy 和 cross-origin resource sharing(CORS)_第3张图片

 

对embed的疑问

同源策略中提到一个概念叫embed cross-origin。对于这些访问,浏览器就“友好”多了。

same-origin policy 和 cross-origin resource sharing(CORS)_第4张图片

 

那么像上面说的,有人在下面的src中填入一个原本会被CORS阻挡住的连接,是不是就能跳过CORS的限制?

过了浏览器还有服务端。

一般服务端默认都有如下配置:

  • 将png,gif,js, css这些可公开的数据, 允许任何人任何方式访问
  • 其他后缀的访问,比如XXX.do, XXX.jsp,哪怕用embed的方式请求,也会被服务端拦截,拒绝访问。CSRF就是手段之一。

注意:

跨域相关的返回header,比如access-control-allow-origin,对embed请求无效。这也是JSONP技术出现的原因。

 

图片被盗链

如果img没有CORS的限制,是不是我可以去随意用img标签盗链别人的图片贴在我自己的网站上?

当然不。如果一个站点不想被别人盗链图片,他就会在服务端里设置:

对于script,png,gif等embed请求,统统检测请求者的referer(为什么不是检测origin?因为img不是脚本跨域请求,浏览器不会自动给这次请求加origin请求头)。

这些embed请求,浏览器都会自动加上referer请求头。

不过referer涉及到了用户的浏览记录隐私,使用下面的标签可以让浏览器不加referer请求头。

为了防止盗链,服务端的逻辑可以是:

先保证自己站点的embed请求都有referfer。服务端再检测所有请求的referer,如果没有referer或者referer不对,都拦截。

图片盗链还有另外一种思路:图片都使用随机名字,并且定期更改。

crossorigin属性

你可能感兴趣的:(same-origin policy 和 cross-origin resource sharing(CORS))