什么是跨域?
简单的说,就是浏览器为了避免xss攻击和csrf攻击,不允许发送请求给与当前源不同源的服务端
同源策略(Same origin policy)是一种约定,它是隔离潜在恶意文件的重要安全机制。
-
它保护了本地数据不被JavaScript代码获取回来的数据污染,因此拦截的是客户端发出的请求回来的数据接收,即请求发送了,服务器响应了,但是无法被浏览器接收(当然可能视浏览器而定,火狐F12是可以看到跨域请求到的cookie,虽然js获取不了)。
-
它也限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。
简而言之就是浏览器规定,A 网站的 JavaScript,不允许和非同源的网站或服务端 C 之间,进行资源的交互。
源包括哪些部分
- 协议
- 域名
- 端口号
以上任意一个不同,请求就会被浏览器拦截。 我之前面试的时候胡言乱语,觉得同一个域名经过dns请求之后如果获取的ip不同,或许也可能跨域, 后来问后端同学发现服务端根本没有同源策略,所以这个是否同源的监测是浏览器完成的,浏览器不会设计的如此复杂,如果等到获取到ip之后才能判断是否同源,这种设计显然是不合理的
跨域会限制什么
- indexDB,localStorage, Cookie (注意Cookie同源策略的判断标准是域名和路径,如果Cookie上设置了Secure属性,那么就会限定此Cookie只能以https传送,以防止中间人攻击)等存储内容
- DOM节点访问
- ajax请求
跨域和预检请求
什么是预检请求?- 在浏览器network中可以看到一种method为options的请求方法
什么时候会触发?- 简单请求不会触发,包括get、post、head请求在不设置
特殊请求头(包括content-type:application/json和自定义请求头)时,其他情况如put、delete请求就是非简单请求 预检请求有什么作用?- 预检是发出非简单请求之前先发出预检请求,查看请求的方法、请求头、源是否被后端允许,不允许则发不出请求,该信息在options请求的响应头中如allow-control-access-origin等
注意-
- 后端在设置allow-control-access-origin等响应头时,需要给预检请求和非简单请求的响应都加上,前者是因为如果不加上就无法通过预检,请求发不出去,后者则是因为如果不加上,浏览器同源策略就会阻止前端对于后端响应的资源的使用(相当于丢弃了响应的结果),就是说虽然请求已经发送,后端也正常响应,但是前端是看不到响应的资源的(当然火狐在network中好像是可以看到的)。
-
- 而且由于同源策略只在浏览器中,所以使用apifox、postman的时候是不受跨域限制的,因此如果使用来历不明的浏览器也可能没有同源策略,这是为了方便进行xsrf攻击
解决方案
-
1. jsonpimg、iframe、script标签的加载外部资源时发的get请求是不受同源策略影响的,jsonp就是基于src加载url不受限实现的,但是这种方案只支持get请求,不推荐
-
2. cors通过后端设置allow-control-access-origin响应头,同源策略就不会拦截这个源发出的请求的响应结果(拦截的是响应而不是请求),当然如果是非简单请求,需要处理一下预检请求使预检通过否则请求发不出
-
3. nginx反向代理简单说就是通过nginx让前端服务与后端服务对于浏览器来说处于同一个源
-
4. websocketws协议是一种支持服务端推送的协议,基于tcp协议,ws会先使用一次http的get请求建立连接,然后升级成ws协议,这个过程中没有跨域限制