关于跨域
一、什么是跨域
跨域就是一个域名请求另外一个域名的资源
二、为什么要引入跨域
原因:浏览器为了维护秩序,实施了同源策略,只有"协议+域名+端口"三者相同的才属于同一域名,只要有一个不同就属于跨域 。浏览器这种规则限制了一个域名与另外一个域名的资源交互。因此当一个域名请求另外一个域名的资源的时候,需要考虑跨域的问题。
三、同源策略如何防止CSRF攻击
- 浏览器为什么要设置这种规则?
原因:为了保证浏览器安全访问,防止CSRF攻击
- 举例说明:
- 假设有一个网站域名为www.a.com的A网站,在该网站里面放置一个域名为www.b.com的B网站的iframe,并且该iframe 100% 宽度高度
- 用户在不知道域名的情况下访问了A网站,但他以为是访问了B网站,所以正常登录了B网站
- 这时A网站通过document.querySelector('iframe').contentWindow.document.cookie脚本就能获得该用户在B网站下的cookie,并且可以随意冒充该用户了。
上述情况,如果同源策略存在,当A网站试图获取B网站的cookie的时候,浏览器会提示一个错误,进行提示
Uncaught DOMException: Blocked a frame with origin "fiddle.jshell.net" from accessing a cross-origin frame.
因此,同源策略使得浏览器限制了跨域获取cookie,也限制了跨域DOM节点的访问,有效的防止的CRSF攻击。
四、怎么解决跨域问题
1、JSONP
2、CORS(跨资源共享)策略
3、document.domain+iframe的设置
4、HTML5的postMessage
5、使用window.name来进行跨域
五、具体的实现
5.1 jsonp
在页面上有三种资源是可以与页面本身不同源的。它们是:js脚本,css样式文件,图片,像淘宝等大型网站,肯定会将这些静态资源放入cdn中,然后在页面上连接,如下所示,它们是可以链接访问到不同源的资源的。
1)<script type="text/javascript" src="某某cdn地址" ></script>
2)<link type="text/css" rel="stylesheet" href="某个cdn地址" />
3)<img src="某个cdn地址" alt=""/>
而jsonp就是利用了script标签的src属性是没有跨域的限制的,从而达到跨域访问的目的。因此它的最基本原理就是:动态添加一个<script>标签来调用服务器提供的js脚本。
JSONP的不足之处:
1、只能使用get方法,不能使用post方法:
我们知道 script,link, img 等等标签引入外部资源,都是 get 请求的,那么就决定了 jsonp 一定是 get 的。但有时候我们使用的 post 请求也成功,为啥呢?这是因为当我们指定dataType:'jsonp',不论你指定:type:"post" 或者type:"get",其实质上进行的都是 get 请求!
2、没有关于 JSONP 调用的错误处理。如果动态脚本插入有效,就执行调用;如果无效,就静默失败。失败是没有任何提示的。例如,不能从服务器捕捉到 404 错误,也不能取消或重新开始请求。不过,等待一段时间还没有响应的话,就不用理它了。
2、CORS策略
原理:
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest
请求,从而克服了AJAX只能同源使用的限制。它为Web服务器定义了一种方式,允许网页从不同的域访问其资源.
CORS系统定义了一种浏览器和服务器交互的方式来确定是否允许跨域请求。 它是一个妥协,有更大的灵活性,但比起简单地允许所有这些的要求来说更加安全。
实现方法:
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
CORS策略的优缺点:
优点:
1、CORS支持所有类型的HTTP请求。
2、使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理。
缺点: 兼容性方面相对差一点,ie10或以上才支持
3、document.domain+iframe的设置 (只有在主域相同的时候才能使用该方法)
浏览器中不同域的框架之间是不能进行js的交互操作的。但是不同的框架之间(父子或同辈),是能够获取到彼此的window对象的,但是,我们也只能获取到一个几乎无用的window对象。比如,有一个页面,它的地址是 http://www.example.com/a.html , 在这个页面里面有一个iframe,它的src是 http://example.com/b.html , 很显然,这个页面与它里面的iframe框架是不同域的,所以我们是无法通过在页面中书写js代码来获取iframe中的东西的。
这个时候,document.domain就可以派上用场了,我们只要把 http://www.example.com/a.html 和 http://example.com/b.html 这两个页面的document.domain都设成相同的域名就可以了。但要注意的是,document.domain的设置是有限制的,我们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。例如:a.b.example.com 中某个文档的document.domain 可以设成a.b.example.com、b.example.com 、example.com中的任意一个,但是不可以设成 c.a.b.example.com,因为这是当前域的子域,也不可以设成baidu.com,因为主域已经不相同了。
前端方面
以前我们使用Ajax,代码类似于如下的方式:
。。。。。。。
4、HTML5的postMessage
原理:
没啥原理,就是一个html5所提供的一个API.--->HTML5 window.postMessage是一个安全的、基于事件的消息API。
在需要发送消息的源窗口调用postMessage方法即可发送消息。其中.源窗口可以是全局的window对象,也可以是以下类型的窗口:
5、使用window.name来进行跨域(相对比较完美的方法)
原理:
当iframe的页面跳到其他地址时,其window.name值保持不变,并且可以支持非常长的 name 值(2MB)。
浏览器跨域iframe禁止互相调用/传值.但是调用iframe时 window.name 却不变,正是利用这个特性来互相传值,当然跨域下是不容许读取ifram的window.name值.
所以这里我们还要准备一个和主页面http://www.a.com/main.html 相同域下的代理页面 http://www.a.com/other.html ,iframe调用子页面 http://www.b.com/data.html
使用方法:
1、 准备三个页面:
http://www.a.com/main.html //应用页面
http://www.a.com/other.html // 代理页面,要求和应用页面在同一个域。一般是一个空的html
http://www.b.com/data.html //应用页面获取数据的页面,简称:数据页面
2、
数据页面将数据传到window.name中去。如下:
http://www.b.com/data.html中的 data.html
转自:
https://www.cnblogs.com/smiler/p/5829621.html
https://blog.csdn.net/weixin_34198453/article/details/91451531