同源策略
这套安全策略由Netscape提出,并延续至今。它规定:JavaScript脚本只能访问与其同一来源的资源(现在很多资源是通过ajax发起异步请求来获取的,如果没有跨域这个是禁止的)。
所谓同源是指,域名,协议,端口相同。不同源的客户端脚本(javascript、ActionScript)在没明确授权的情况下,不能读写对方的资源。严格隔离不相关的网站提供的内容,防止客户端数据机密性或完整性丢失。
假设你已经成功登录Gmail服务器,同时在同一个浏览器访问恶意站点(另一个浏览器选项卡)。没有同源策略,攻击者可以通过JavaScript获取你的用户信息,你的邮件以及其他敏感信息,比如说阅读你的私密邮件,发送虚假邮件,看你的聊天记录等等。假如把这个换成银行账户,那就很恐怖了。
可以说同源策略是现如今浏览器安全的基石。但是如果不能突破同源策略,把所有的资源放在同一服务器下,现在看来是不现实,必须有一中方式去平衡这种安全和便捷的机制–跨域。现在一般的跨域使用的是CORS(基本所有浏览器支持)和JSONP(一些比较的老的应用使用)。
CROS跨域
CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
简单说一下我对CROS的理解。就相当于我想跟一个邻居借东西(浏览器向服务器发送跨域请求)。我首先要去敲门,然后就是几种情况,一种是邻居家里你敲门没有反应(服务器端没有设置跨域),你跟不知道邻居家里的具体情况,借东西肯定是失败的。一种是邻居进行了应答,但是告诉你我跟你不熟,不借东西给你。另外一种就是邻居进行了应答,并借给你东西。
要了解CROS跨域,首先需要知道浏览器在ajax发起跨域请求的时候做了什么事。每次浏览器检查到这个请求是跨域请求时,会在请求的头部添加一些附加的头信息,根据请求的不同,有时会多发起一次请求
但是这些用户是感觉不到,前端的ajax调用也没有发什么变化,改变的是服务器端的回应。所以cros跨域由于浏览器的支持,现在只要在服务器端,也就是后端进行配置就可以了。
cros分类
浏览器将cros的跨域请求分为两种:一种是简单请求,一种的非简单请求,两种的区别就是在发起非简单请求的时候,浏览器会在请求的前面先发起一次预请求,看请求的后端是否允许当前这个域名和这个方法进行访问。
1 | 简单请求(不满足以下条件的都是非简单请求): |
cros的简单请求
对于简单请求的cros跨域请求,浏览器会在就是在头信息之中,增加一个Origin
字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)服务器根据这个值,决定是否同意这次请求。
如果Origin
的字段在服务器端允许的范围内,服务器成功响应,会在返回的头信息中多几个字段
1 | //该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。 |
如果Origin
指定的域名不在许可范围内。服务器也会正常的返回HTTP的回应(状态吗有可能是200),只是头信息里面不会增加上面的字段。浏览器收到回应后 会检测是否有Access-Control-Allow-Origin
字段,如果没有回抛出一个错误,被XMLHttpRequest的onerror回调函数捕获
非简单请求
非简单请求就是不满足简单请求条件的都是非简单请求,值得注意的是Content-Type: application/josn
都是非简单请求。
浏览器如果检测到发起的请求是非简单请求,会在正式发起HTTP请求前,浏览器会自动发起一次HTTP查询请求,称为”预检”请求(preflight)。
预请求的方法是OPTIONS
,这个方法和GET,POST等方法是一样的。这个方法表示请求是用来询问的服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest
请求,否则就报错。
1 | 一个预检请求 |
一旦服务器通过了”预检”请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段。
beego的跨域
在工作中用beego框架遇到的跨域问题的解决
1 | func main() { |
JSONP的简介
CORS与JSONP的使用目的相同,但是比JSONP更强大。
JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。