什么是跨域?什么是跨站资源共享?什么是CROS?
跨域与同源策略
1. 什么是域?什么是同源
一个url(统一资源定位符)的基本组成部分: 协议 :// 域名(或者是ip) : 端口(默认80) / 路径;
判断同源的三要素是:协议、端口、域名。
2. 与域有关的浏览器动作:
- 1.) 资源跳转: A链接、重定向、表单提交
2.) 资源嵌入: <link>、<script>、<img>、<frame>等dom标签,还有样式中background:url()、@font-face()等文件外链
3.) 脚本请求: js发起的ajax请求、dom和js对象的跨域操作等
3. 什么是同源策略?
同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指”协议+域名+端口”三者相同,即便两个不同的域名指向同一个ip地址,也非同源。
同源策略限制以下几种行为:
1.) Cookie、LocalStorage 和 IndexDB 无法读取
2.) DOM 和 Js对象无法获得
3.) AJAX 请求不能发送
不受同源限制的情况:
1.) script标签允许跨域嵌入脚本,稍后介绍的JSONP就是利用这个“漏洞”来实现。
2.) img标签、link标签、@font-face不受跨域影响。
3.) video和audio嵌入的资源。
4.) iframe载入的任何资源。(不是iframe之间的通信)
5.)
4. 如何获取(get)和设置(set)域(domain)
get: document.domain;
set: document.domain=”XXXX” (赋值改写)
//初始值 “home.example.com”
document.domain = “example.com”; //OK
document.domain = “home.example.com”; //NO,不能由松散变紧绷
document.domain = “example”; //NO,必须有一个点号
document.domain = “another.com”; //NO, 必须是有效域前缀或其本身
同源策略之cookie、iframe、cros介绍
1. 关于Cookie和Session:
说到同源策略,必不可少的就是Cookie这个东西了。
而讲到Cookie,跟它关联在一起的又有Session。
对于这两者,具体去传送门查阅。
做个小结:
- Cookie受到浏览器同源策略的限制,A页面的Cookie无法被B页面的Cookie访问和操作。
- Cookie最大存储容量一般为4KB,由服务器生成,在HTTP报文首部设置Set-Cookie可以指定生成Cookie的内容和生命周期,如果由浏览器生成则在关掉浏览器后失效。
- Cookie存储在浏览器端,由于每次发送HTTP请求默认会把Cookie附到HTTP首部上去,所以Cookie主要用来身份认证,而不用来存储其他信息,防止HTTP报文过大。
- Session存储在服务器,主要与Cookie配合使用完成身份认证和状态保持的功能。只有Cookie或只有Session都无法完成身份认证和状态保持的功能。
session和cookie做状态保持和身份验证————
假设现在有一个学生信息管理系统,此时数据库已经有学生的相关信息。(账号、密码、个人信息等等)
然后当学生登录这个系统,通过POST请求把用户的账户密码发送到后台服务器。当后台服务器接收到这些参数的时候,会跟数据库保存的记录进行匹配。
一旦匹配成功,也就是用户的账号密码都正确的情况下,这个时候后台服务器会在Session中记录一个值,可以是用户名或者其他能够唯一标识用户的字段。
当把这个值保存在Session中后,后台服务器会返回响应告知客户端登录成功,可以进行后续的操作。此时,后台服务器会在HTTP响应报文中添加一个字段Set-Cookie,它的值是当前Session的SessionID,(这个SessionID是指向我们当前的那个Session的,在Node的Express中express-session会封装好这个过程)当然还会设置Cookie的其他属性,比如说过期时间Expires等等。
当浏览器接收到这个HTTP响应报文的时候,就会在本地设置一个Cookie,它的过期时间由响应报文中Set-Cookie中的Expires字段的值决定,如果为空,则关闭浏览器(即会话结束时)后失效。
之后,每次向后台服务器发送请求的时候,浏览器默认会把这个Cookie加在HTTP请求报文的Cookie中。这样,每次后台服务器接收到请求的时候,会根据Cookie中的SessionID去找到我们的Session。
假如这个SessionID映射得到Session,那么这个时候说明浏览器是已经登录过了。于是,就可以进行后续的一些相关的操作。
另外,值得一提的是,Session机制决定了当前客户只会获取到自己的Session,而不会获取到别人的Session。各客户的Session也彼此独立,互不可见。也就是说,当多个客户端执行程序时,服务器会保存多个客户端的Session。获取Session的时候也不需要声明获取谁的Session。
这就是Cookie和Session做状态保持和身份验证的一个具体的例子。
2. 关于iframe:
同源限制有一个不得不提的就是iframe,iframe可以在父页面中嵌入一个子页面,在日常开发中一旦使用,避免不了的就要涉及到不同的iframe页面进行通信的问题,可能是获得其他iframe的DOM,或者是获取其他iframe上的全局变量或方法等等。
同源下的iframe,也就是iframe中的src属性的URL符合同源的条件,那么通过iframe的contentDocument和contentWindow获取其他iframe的DOM或者全局变量、方法都是很简单的事情。
那如果是非同源的两个iframe,单纯的通过变量访问的方式就受到同源限制了。
非同源的两个iframe,单纯的通过变量访问的方式就受到同源限制了。为了解决这个问题,HTML5引入了一个新的API:###postMessage###,主要就是用来解决存在跨域问题的iframe页面之间通信的问题。
postMessage API
postMessage接受两个参数,一个是要传送的data,另外一个是目标窗口的源,如果想传给任何窗口,可以设置成*。
目标页面接收信息的时候,使用的是window.addEventListener(“message”, function(e) {})。
把B页面用iframe嵌在A页面下面的栗子(A-http://localhost:4002/parent.html,B-http://localhost:4003/child.html)
|
|
3. CORS-跨域资源共享:
- 简单请求和非简单请求
简单请求:
- 请求方法:HEAD、GET、POST之一;
- 请求头 Content-Type只限于三个值(表单提交):application/x-www-form-urlencoded、multipart/formdata、text/plain。
- 非简单请求:是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json,非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为”预检”请求(preflight)。
一旦浏览器通过了“预检”,以后每次浏览器正常的CORS请求,都跟简单请求一样,会有一个Origin头信息字段。服务器的回应,也都有一个Access-Control-Allow-Origin头信息字段。如果开启了Cookie设置,那还有一个Access-Control-Allow-Credentials:true。
需要浏览器和服务器同时支持。
原理:使用”Origin:”请求头和”Access-Control-Allow-Origin”响应头来扩展HTTP。其实就是利用新的HTTP头部来进行浏览器与服务器之间的沟通。
针对前端代码而言,变化的地方在于相对路径需改为绝对路径。
12345678//以前的方式var xhr = new XMLHttpRequest();xhr.open("GET", "/test", true);xhr.send();//CORS方式var xhr = new XMLHttpRequest();xhr.open("GET", "http://segmentfault.com/test", true);xhr.send();针对服务器代码而言,需要设置Access-Control-Allow-Origin,列出源或使用通配符来匹配所有源。
优点:
CORS支持所有类型的HTTP请求。
使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据
不足:
不能发送和接收cookie
更新:服务端可以通过设置Access-Control-Allow-Credentials该字段来表示是否允许发送Cookie。发送ajax请求时,需配置withCredentials属性。
不能使用setRequestHeader()设置自定义头部
兼容IE10+
CORS不能发送和接收cookie解决办法:
服务器返回的响应的与CORS有关的几个头信息字段:
Access-Control-Allow-Origin: http://hello.world.com或者*【必须】
Access-Control-Allow-Credentials: true 【可选】它的值是一个布尔值,表示是否允许发送Cookie
Access-Control-Expose-Headers: FooBar 【可选】XMLHttpRequest对象的getResponseHeader()
方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。
ORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials字段。另一方面,开发者必须在AJAX请求中打开withCredentials属性。
需要注意的是,如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无法读取服务器域名下的Cookie。
更详细的CROS,请移步阮一峰的《跨域资源共享》一文
常用跨域解决方案
1、 通过jsonp跨域
2、 document.domain + iframe跨域
3、 location.hash + iframe
4、 window.name + iframe跨域
5、 postMessage跨域
6、 跨域资源共享(CORS)
7、 nginx代理跨域
8、 nodejs中间件代理跨域
9、 WebSocket协议跨域
通过jsonp跨域
通常为了减轻web服务器的负载,我们把js、css,img等静态资源分离到另一台独立域名的服务器上,在html页面中再通过相应的标签从不同域名下加载静态资源,而被浏览器允许,基于此原理,我们可以通过动态创建script,再请求一个带参网址实现跨域通信。
参考文献: