跨域的产生与方法

跨域

跨域产生的原因

浏览器的同源策略导致了跨域,是浏览器在搞事情。其实,同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。
若没有同源策略,将会有很大的危险。

没有同源策略限制的接口请求

有一个小小的东西叫cookie大家应该知道,一般用来处理登录等场景,目的是让服务端知道谁发出的这次请求。如果你请求了接口进行登录,服务端验证通过后会在响应头加入Set-Cookie字段,然后下次再发请求的时候,浏览器会自动将cookie附加在HTTP请求的头字段Cookie中,服务端就能知道这个用户已经登录过了。知道这个之后,我们来看场景:

这就是传说中的CSRF攻击。

没有同源策略限制的Dom查询

1
2
3
4
5
6
7
// HTML
<iframe name="yinhang" src="www.yinhang.com"></iframe>
// JS
// 由于没有同源策略的限制,钓鱼网站可以直接拿到别的网站的Dom
const iframe = window.frames['yinhang']
const node = iframe.document.getElementById('你输入账号密码的Input')
console.log(`拿到了这个${node},我还拿不到你刚刚输入的账号密码吗`)

跨域的方法

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.htmlhttp://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。