跨域
跨域产生的原因
浏览器的同源策略导致了跨域,是浏览器在搞事情。其实,同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。
若没有同源策略,将会有很大的危险。
没有同源策略限制的接口请求
有一个小小的东西叫cookie大家应该知道,一般用来处理登录等场景,目的是让服务端知道谁发出的这次请求。如果你请求了接口进行登录,服务端验证通过后会在响应头加入Set-Cookie字段,然后下次再发请求的时候,浏览器会自动将cookie附加在HTTP请求的头字段Cookie中,服务端就能知道这个用户已经登录过了。知道这个之后,我们来看场景:
你准备去清空你的购物车,于是打开了买买买网站www.maimaimai.com,然后登录成功,一看,购物车东西这么少,不行,还得买多点。
你在看有什么东西买的过程中,你的好基友发给你一个链接www.nidongde.com,笑嘻嘻地跟你说:“你懂的”,你毫不犹豫打开了。
这就是传说中的CSRF攻击。
没有同源策略限制的Dom查询
有一天你刚睡醒,收到一封邮件,说是你的银行账号有风险,赶紧点进www.yinghang.com改密码。你吓到了,赶紧点进去,还是熟悉的银行登录界面,你果断输入你的账号密码,登录进去看看钱有没有少了。
睡眼朦胧的你没看清楚,平时访问的银行网站是www.yinhang.com,而现在访问的是www.yinghang.com,这个钓鱼网站做了什么呢?
1 | // HTML |
跨域的方法
jsonp
jsonp是为了解决跨域请求资源而产生的解决方案,是一种依靠开发人员创造出的一种非官方跨域数据交互协议。
demo:
前端代码:1
2
3
4
5
6<script>
function dosomething(jasondata){
//处理获得的json值
}
</script>
<script src="http://example.com/data.php?callback = dosomething"></scipt>
后台代码:1
2
3
4<?php
$callback = $GET['callback'];//得到回调函数名
$data = array('a','b','c');//要返回数据
echo $callback.'('.json_encode($data).')';//输出
结果:1
dosomething{['a','b','c']}
这样jsonp的原理就很清楚了,通过script标签引入一个js文件,这个js文件载入成功后会执行我们在url参数中指定的函数,并且会把我们需要的json数据作为参数传入。所以jsonp是需要服务器端的页面进行相应的配合的。
document.domain跨子域
览器都有一个同源策略,其限制之一就是第一种方法中我们说的不能通过ajax的方法去请求不同源中的文档。 它的第二个限制是浏览器中不同域的框架之间是不能进行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,因为主域已经不相同了。1
2
3
4
5
6
7<iframe src = "http://example.com/b.html" id="iframe" onload="test()"></iframe>
<script>
document.domain = 'example.com';//设置成主域
function test(){
alert(document.getElementById('iframe').contentWindow);
}
</script>
将两个页面的主域都设置成example.com,就可以跨子域通过js访问到iframe的各种属性和对象。
关于跨域,还有一篇推荐文章https://www.cnblogs.com/2050/p/3191744.html。