Java深入学习13其他思科DevNet

什么是跨域请求以及实现跨域的方案

2017-10-07  本文已影响877人  ken_ljq

前言:对于跨域请求,很早之前就有去了解过,但因为一直关注的都是服务器后端开发,故也就仅仅停留在概念的理解上而没有机会在实际开发场景中接触得到。最近在公司的开发任务中,需要接触到 Ajax 跨域请求,由于之前没有遇到过类似的问题,在开发过程中遇到不少困难,也查阅了不少资料和博客。在这过程中收获了不少,故特意写下以下文章总结,如果文章有什么不足之处,还望各位指出。

什么是跨域请求

概述

​ 在 HTML 中,<a>, <form>, <img>, <script>, <iframe>, <link> 等标签以及 Ajax 都可以指向一个资源地址,而所谓的跨域请求就是指:当前发起请求的域与该请求指向的资源所在的域不一样。这里的域指的是这样的一个概念:我们认为若协议 + 域名 + 端口号均相同,那么就是同域。

​ 举个例子:假如一个域名为aaa.cn的网站,它发起一个资源路径为aaa.cn/books/getBookInfo的 Ajax 请求,那么这个请求是同域的,因为资源路径的协议、域名以及端口号与当前域一致(例子中协议名默认为http,端口号默认为80)。但是,如果发起一个资源路径为bbb.com/pay/purchase的 Ajax 请求,那么这个请求就是跨域请求,因为域不一致,与此同时由于安全问题,这种请求会受到同源策略限制。

跨域请求的安全问题

​ 通常,浏览器会对上面提到的跨域请求作出限制。浏览器之所以要对跨域请求作出限制,是出于安全方面的考虑,因为跨域请求有可能被不法分子利用来发动 CSRF攻击。

CSRF攻击:

​ CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。CSRF攻击者在用户已经登录目标网站之后,诱使用户访问一个攻击页面,利用目标网站对用户的信任,以用户身份在攻击页面对目标网站发起伪造用户操作的请求,达到攻击目的。

​ CSRF 攻击的原理大致描述如下:有两个网站,其中A网站是真实受信任的网站,而B网站是危险网站。在用户登陆了受信任的A网站是,本地会存储A网站相关的Cookie,并且浏览器也维护这一个Session会话。这时,如果用户在没有登出A网站的情况下访问危险网站B,那么危险网站B就可以模拟发出一个对A网站的请求(跨域请求)对A网站进行操作,而在A网站的角度来看是并不知道请求是由B网站发出来的(Session和Cookie均为A网站的),这时便成功发动一次CSRF 攻击。

​ 因而 CSRF 攻击可以简单理解为:攻击者盗用了你的身份,以你的名义发送而已请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......造成的问题包括:个人隐私泄露以及财产安全。

​ 因此,大多数浏览器都会跨域请求作出限制,这是从浏览器层面上的对 CSRF 攻击的一种防御,但是需要注意的是在复杂的网络环境中借助浏览器来防御 CSRF 攻击并不足够,还需要从服务端或者客户端方面入手防御。详细可以参考这篇文章浅谈CSRF攻击方式

同源策略(Same-origin Policy)

概述

同源策略的含义

同源的具体含义

跨域解决方法

虽然在安全层面上同源限制是必要的,但有时同源策略会对我们的合理用途造成影响,为了避免开发的应用受到限制,有多种方式可以绕开同源策略,下面介绍的是经常使用的 JSONP, CORS 方法。

JSONP

原理:
示例:

首先当前页面中声明有这样的一个函数,它将作为 JSONP 的回调函数处理作为函数参数传入的数据

<script type="text/javascript">
    function dosomething(jsondata){
        //处理获得的json数据
    }
</script>

然后,我们就可以借助 <script><img><iframe> 等标签可以引入不同域资源的特性,将需要发送的请求的路径作为src参数,其中需要注意的是:需要告知服务端回调函数的函数名。

<script src="http://example.com/data.php?callback=dosomething"></script>

这时服务端在返回数据的时候,就会返回一端 Javascript 代码,在 Javascript代码中调用了回调函数,并且需要返回的数据作为回调函数的参数

dosomething(['a','b','c']);

最后页面成功加载了刚才指定路径的资源后,将会执行该 Javascript 代码,dosomething函数将执行,这时一次跨域请求完成。

另外,如果页面引入了 jQuery,那么可以通过它封装的方法很方便的实现JSONP操作了

// Using YQL and JSONP
$.ajax({
    url: "http://query.yahooapis.com/v1/public/yql",
 
    // The name of the callback parameter, as specified by the YQL service
    jsonp: "callback",
 
    // Tell jQuery we're expecting JSONP
    dataType: "jsonp",
 
    // Tell YQL what we want and that we want JSON
    data: {
        q: "select title,abstract,url from search.news where query=\"cat\"",
        format: "json"
    },
 
    // Work with the response
    success: function( response ) {
        console.log( response ); // server response
    }
});
优缺点:

JSONP 的优点是:它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中都可以运行。

JSONP 的缺点是:它只支持 GET 请求,而不支持 POST 请求等其他类型的 HTTP 请求

CORS

介绍

​ 跨源资源共享 Cross-Origin Resource Sharing(CORS) 是一个新的 W3C 标准,它新增的一组HTTP首部字段,允许服务端其声明哪些源站有权限访问哪些资源。换言之,它允许浏览器向声明了 CORS 的跨域服务器,发出 XMLHttpReuest 请求,从而克服 Ajax 只能同源使用的限制。

​ 另外,规范也要求对于非简单请求,浏览器必须首先使用 OPTION 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求,在服务器确定允许后,才发起实际的HTTP请求。对于简单请求、非简单请求以及预检请求的详细资料可以阅读HTTP访问控制(CORS)

HTTP 协议 Header 简析

下面对 CORS 中新增的 HTTP 首部字段进行简析:

示例

假设我们在 bbb.cn 域名下,发送一个 Ajax 请求到 aaa.cn 域名,其路径如下:http://aaa.cn/localserver/api/corsTest 。由于同源策略,这样的 Ajax 请求将会被浏览器所拦截,得到下面的信息:

若想能够发送跨域请求,我们只需要在服务器的响应中配置适当的CORS HTTP 首部字段就可以了,例如可以加入以下的首部字段:

Access-Control-Allow-Methods:*

此时,Ajax请求就可以顺利的发送和接收了,对应的请求和响应头部如下:

对于在 Java Web 项目中,如何在 Servlet 或这 Spring MVC 中配置 CORS 可以阅读文章Spring MVC 实现 CORS 跨域

与 JSONP 的比较

Reference

上一篇 下一篇

猜你喜欢

热点阅读