跨域是每个程序员都躲不过的一个问题,无论是面试还是现实中的开发。既然如此我们就来详细讲解一下什么是跨域,该怎么解决这个跨域问题。
老规矩,先上定义,先从定义下手。
什么是跨域
定义:跨域,就是指浏览器不能执行其他网站的脚本。
那为什么会产生跨域这个问题呢?为什么不能再浏览器上执行其他网站的脚本呢?
这里就涉及到我们的浏览器的同源策略了,
那你可能又要问什么是同源策略?浏览器为什么要使用这个同源策略。不使用这个同源策略不就不会产生跨域这个问题了吗?不就没有那么多事情了吗?我们接下来就老好好解开这个疑问?
什么是同源策略
定义:同源策略是一个重要的安全策略,它可以限制一个来源,或者它的脚本的另一个来源,可以与另一个资源进行有效的合作。可以帮助阻止间接文档,减少可能被攻击的文档。
怎么样的才是同源
定义:如果 URL 的协议、端口(en-US)(如果有指定的话)和主机都一样的话,那么两个 URL 是同一个端口。方案也被称为“组协议/主机/元元”,或者直接是“元组”。
其中,源=协议+主机+端口,只有这三个要素相同,两个源才相同,称之为同源,如果两个源不同,则称之为跨源或跨域。
示例:
与 URLhttp://store.company.com/dir/page.html的源对比的示例:
网址 | 结果 | 原因 |
---|---|---|
http://store.company.com/dir2/other.html | 同源 | 只是路径不同 |
http://store.company.com/dir/inner/another.html | 同源 | 只是路径不同 |
https://store.company.com/secure.html | 失败 | 不同协议 |
http://store.company.com:81/dir/etc.html | 失败 | 端口不同(http://默认端口为 80) |
http://news.company.com/dir/other.html | 失败 | 主机不同 |
那浏览器为什么要使用同源策略呢?
如果我们对浏览器为什么要使用同源策略有疑问,我们不妨反过来思考。如果没有同源策略会怎么样呢?
没有同源策略限制的两大危险场景
据我了解,浏览器是从两个方面去做这个同源策略的,一是针对接口的请求,二是针对Dom的查询。试想一下没有这样的限制上述两种动作有什么危险。
没有同源策略限制的接口请求
cookie大家应该知道,一般用来处理登录等场景,目的是让服务端知道谁发出的这次请求。如果你请求了接口进行登录,服务端验证通过后会在响应头加入Set-Cookie字段,然后下次再发请求的时候,浏览器会自动将cookie附加在HTTP请求的头字段Cookie中,服务端就能知道这个用户已经登录过了。知道这个之后,我们来看场景: 1.你准备去清空你的购物车,于是打开了买买买网站www.maimaimai.com,登录成功, 2.你在看有什么东西买的过程中,你的好基友发给你一个链接www.nidongde.com,一脸yin笑地跟你说:“你懂的”,你毫不犹豫打开了。 3.你饶有兴致地浏览着www.nidongde.com,谁知这个网站暗地里利用浏览器的安全漏洞来进行黑客行为,盗取你的钱!由于没有同源策略的限制,它向www.maimaimai.com发起了请求!聪明的你一定想到上面的话“服务端验证通过后会在响应头加入Set-Cookie字段,然后下次再发请求的时候,浏览器会自动将cookie附加在HTTP请求的头字段Cookie中”,这样一来,这个不法网站就相当于登录了你的账号,可以为所欲为了!如果这不是一个买买买账号,而是你的银行账号,那就更危险了…… 这就是传说中的CSRF攻击浅谈CSRF攻击方式。 看了这波CSRF攻击我在想,即使有了同源策略限制,但cookie是明文的,还不是一样能拿下来。于是我看了一些cookie相关的文章。知道了服务端可以设置httpOnly,使得前端无法操作cookie,如果没有这样的设置,像XSS攻击就可以去获取到cookieWeb安全测试之XSS;设置secure,则保证在https的加密通信中传输以防截获。
没有同源策略限制的Dom查询
我们来看场景:
1.有一天你刚睡醒,收到一封邮件,说是你的银行账号有风险,赶紧点进www.yinghang.com改密码。你吓尿了,赶紧点进去,还是熟悉的银行登录界面,你果断输入你的账号密码,登录进去看看钱有没有少了。 2.睡眼朦胧的你没看清楚,平时访问的银行网站是www.yinhang.com,而现在访问的是www.yinghang.com,这个钓鱼网站做了什么呢?
// 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
在HTML标签里,一些标签比如script、img这样的获取资源的标签是没有跨域限制的,利用这一点,我们可以这样干: