Http同源策略与跨域方法

一 概述

同源策略是web安全策略中的一种,也是非常重要的一种,同源策略明确规定了不同域的客户端在没有被明确的授权的情况下,不能读写对方的资源。、

二 同源分析

同源是指请求的URI(统一资源标识符),网络协议,主机名(域名),端口号相同。但是IE浏览器同源不包括端口号。

例如URL:http://www.example.com:8080/test/index.html,分析一下几种同源情况:

URL 是否同源 结果分析
http://www.example.com:8080/test/index1.html 同源 相同协议,域名,端口
http://www.example.com:8080/index.html 同源 相同协议,域名,端口
http://www.example.com/test/index.html 看情况 看浏览器,默认8080端口或者IE忽略端口的情况下同源
https://www.example.com:8080/test/index.html 不同源 不同协议
http://www.example.com:80/test/index.html 看情况 看浏览器,IE忽略端口的情况下同源
http://www.apple.com:8080/index.html 不同源 不同域名

三 同源策略的对非同源的主要限制范围

  1. Cookie,LocalStorage和IndexDB无法读取。
  2. DOM无法获得。
  3. AJAX请求无法发送。

这些限制对于安全方面是很有必要的,但是实际开发过程中,会搭建服务其集群,会把客户端页面放到一个单独的服务器中,此时就会出现不同源的情况。这时候如果想要不同源的网站之间进行数据交互,我们需要使用到跨域请求。

四 跨域请求方案

      跨域请求报错:

XMLHttpRequest cannot load http://localhost:8080/test.json. No 'Access-control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8081' is therefore not  allowed access.

      1 JSONP(JSON with Padding)

JSONP可以解决主流浏览器的跨域数据访问问题,实际上js是不可以请求数据但是可以跨域请求js脚本。其原理为服务端返回一个定义好的js函数的调用 ,并且将服务器的数据封装成js函数参数的形式传递过来,最后执行函数返回后端数据,这个方法需要前后端配合,而且JSONP仅支持Get请求。

var URL_Serv:"http://localhost:8080/test.json";

/**
 *使用ajax内置方法getJSONP返回js脚本实现跨域请求
 *将请求的服务端数据URL_Serv作为js方法的参数
 *自定义的回调函数test.getDataService。
 *test.getDataService(test.json)。
**/
$.getJSONP(this.URL_Serv, test.getDataService)

      2. CORS跨域资源共享

跨域请求的字段及其含义:

Access-Control-Allow-Origin

该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。

 /*服务器端 Access-Control-Allow-Credentials = true时,参数Access-Control-Allow- Origin 的值不能为'*',如果origin.equals('*'),表示所有域名都可以,但跨域不支持cookie。oirgin可以设置特定的域名如:www.example.com,进行跨域请求。*/

Access-Control-Allow-Credentials

该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。

Access-Control-Expose-Headers

该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。上面的例子指定,getResponseHeader('FooBar')可以返回FooBar字段的值。

Access-Control-Allow-Methods

该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求。

Access-Control-Allow-Headers

如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。

Access-Control-Max-Age

该字段可选,用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此期间,不用发出另一条预检请求。

XMLHttpRequest是一个JavaScript内置对象,使得JavaScript可以进行异步的HTTP通信。新版的XMLHttpRequest对象,可以向不同域名的服务器发送Http请求。这叫做“跨域资源共享”(Cross-origin resource sharing,简称CORS)。

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

实现跨域的前提:1.浏览器支持这个功能(兼容IE10+)。2.服务器必须允许这种跨域。

服务器支持跨域过滤前端请求基于注解的代码,添加请求响应头:

import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class HeaderFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, 
    FilterChain filterChain) throws IOException, ServletException {

        HttpServletResquest request = (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse)servletResponse;

        Strign origin = request.getHeader("origin");

        //允许那些域访问
        response.setHeader("Access-Control-Allow-Origin", origin);
        //允许那些请求方法
        response.setHeader("Access-Control-Allow-Methods", "POST,GET");
        //是否携带Cookie
        response.setHeader("Access-Control-Allow-Credentials", "true");
        //它表明了这个询问结果的有效期,后面浏览器在有效期内也可以不必再次询问
        response.setHeader("Access-Control-Max-Age", "3600");
        //允许那些请求头字段
        response.setHeader("Access-Control-Allow-Headers", "Content-Type, 
        Access-Control-Allow-Headers, Authorization, X-Requested-With");

        filterChain.doFilter(servletRequest,response);
    }

    @Override
    public void destroy() {

    }
}

CORS的具体实现流程:

  1. 浏览器发送跨域请求(实际上浏览器不会直接发送请求,而是现发送一个不带任何参数的试探请求OPTIONS,检测服务器是否允许跨域,如果允许跨域同时设置的请求和响应头一致,才会发送第二次具体的请求。)
  2. 服务端接收到跨域请求之后,在响应头中添加Access-Control-Allow-Origin Header资源权限配置,发送响应。
  3. 浏览器收到响应后,查看是否设置了header('Access-Control-Allow-Origin:请求源域名或者*');如果当前域已经授权了,则将结果返回给浏览器,否则浏览器忽略此次响应。

实际上,跨域行为是浏览器行为,响应回来的是浏览器安全机制的限制,对跨域响应内容进行了忽略。服务器与服务器之间并不存在跨域问题。

五 JSONP与CORS的比较

  • JSONP能够支持老版本的浏览器,兼容性比较好,而CORS需要浏览器支持CORS才行。
  • JSONP仅仅支持GET请求,发送的数据量有限,使用比较麻烦。
  • CORS使用简单,只要服务单设置允许跨域,对于客户端来说,同一般的GET,POST请求类似,没有什么区别。

跨域的安全行问题:因为跨域是需要前端同服务端配合控制的,这样无论是JSONP还是CORS,如果没有服务端的允许,浏览器都是无法实现跨域的。

提示:微服务项目工作中,可以采用一个独立的模块管理不同的请求避免跨域访问,实际上跨域访问是存在一定的风险的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章