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

本文深入解析同源策略的原理与应用,探讨浏览器如何保障网页安全,防止跨站请求伪造。同时,详述CORS机制,解释如何通过设置HTTP头部实现跨域资源共享,涵盖预检请求、响应头及常见问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 同源策略和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的说法:

  • 跨域写请求一般是被允许的(比如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预检测机制。

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

 

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

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/

 

对embed的疑问

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

 

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

<img src="">

过了浏览器还有服务端。

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

  • 将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请求头。

<meta name="referrer" content="no-referrer">

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

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

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

crossorigin属性

<img>, <script>  等标签有一个crossorigin属性

https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes

加上这个标签,把embed请求变成CORS请求。

谁会这么做呢?要知道CORS比embed有更多的约束。

当然是合法的访问者愿意这么做啦。

服务端不提供embed方式的图片数据,访问者统统要用CORS的方式,并且服务端配置了跨域origin的白名单。

 

JS与crossorigin

embed方式引入的跨域脚本,如果有异常,不会在window.onerror 中抛出。这是出于安全考虑。

因为按照同源策略,脚本是可以访问到本地的同源数据(cookie等)。

如果想要这些异常信息,需要用crossorigin属性,走CORS请求。

 

document.domain的修改

api document.domain支持修改当前doucment的domain值。由于同源的判断是基于这个domain属性的,因此修改有如下的限制:

这段话提到了一个概念:effective domain

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

 

iframe

iframe也收到同源策略的保护

iframe是embed的一种,因此需要服务端做iframe的安全配置。

参考:

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options 

access-control-allow-origin 返回header对于iframe无效(ifram也是embed的一种)

 

window.open

window.open 方法可以打开一个新的tab,并放回一个window对象。不过这个window对象也受同源策略的保护。

跨域脚本只允许访问该对象中的部分属性和部分方法。

 

具体参考:

https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Cross-origin_script_API_access\

 

不允许用脚本修改的请求header

最重要的是origin和referer,是不能通过脚本修改的。

https://developer.mozilla.org/zh-CN/docs/Glossary/%E7%A6%81%E6%AD%A2%E4%BF%AE%E6%94%B9%E7%9A%84%E6%B6%88%E6%81%AF%E9%A6%96%E9%83%A8

 

CORB

https://chromium.googlesource.com/chromium/src/+/master/services/network/cross_origin_read_blocking_explainer.md

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值