同源策略与CORS(ajax跨域)

跨域问题系列文章

1. 同源策略与CORS(跨域请求的起源)
2. SpringBoot2.x整合CORS解决跨域问题(两种方案)
3. 跨域预检请求进行权限认证(复杂跨域请求的处理)
4. Filter返回失败如何使用CORS配置(SendError和setStatus的区别)

1. 同源策略

浏览器的安全基石是“同源策略”,目前所有的浏览器都实行这个策略。

同源策略限制了:从一个源加载的文档或脚本去另一个源进行资源交互。

同源指的是协议://域名:端口 相同,可以理解为一个服务器

同源策略主要是对js脚本有限制,主要表现为下面三点:

  1. 无法使用js脚本获取非同源Cookie,LocalStorage和IndexDB数据。
  2. 无法使用js获取非同源的DOM。
  3. 无法使用js发送非同源的AJAX请求,更确切的话,js可以向非同源的服务器发送请求,不能携带非同源服务器的Cookie,最后服务器返回的数据会被浏览器拦截。

2. CSRF安全问题

如果没有同源策略,可能会造成Cross SiteRequest Forgery 跨站点请求伪造[可绕斯][赛特][否则瑞],攻击者会伪造客户端的请求向服务器进行攻击。

CSRF安全问题.png

服务器对跨域访问的检查就可以有效避免或限制这个行为。因为正常访问和伪造请求的区别就在于请求的源页面是否是服务器能够识别的页面。

3. CORS解决跨域问题

既然请求头中会携带Origin(请求的源头)字段,那么服务器只需要验证该字段是否符合预期即可。

关于跨域问题和安全性的一点理解

web开发的跨域问题详解

要解决跨域问题,首先要知道跨域问题产生的原因:

  • 浏览器的限制(服务端收到了请求并正确返回);
  • 发送的是XMLHttpRequest请求,也就是XHR请求;
  • 请求了不同域的资源;

CORS是一个W3C标准,全程是跨域资源共享(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发送XMLHttpRequest请求,从而克服Ajax只能同源的限制。CORS基于http协议关于跨域方面的请求,使用时,客户端浏览器直接异步请求被调用端的服务端,在响应头增加响应字段,告诉浏览器允许跨域。

跨域问题的异常信息

我们可以看到具体的异常:服务端没有设置Access-Control-Allow-Origin这个响应头从而导致出错,那么通过设置Access-Control-Allow-Origin:*这个响应头,我们可以解决问题。但是,这种设置能满足所有情况吗?更进一步来说,使用CORS时浏览器如何检查跨域错误?虽然浏览器异常,但是在之前服务端已经接受了请求,那么浏览器是先发出请求再判断的吗?

3.1 浏览器如何检查跨域错误

当浏览器会检测到ajax请求的域和当前域不一致时,会在请求头增加origin字段,然后检查服务端响应头Access-Control-Allow-Origin[额老],如果不存在或不匹配,则报跨域错误。

浏览器检查跨域原理

3.2 浏览器总是先发出请求,然后根据响应来判断吗?

对于简单请求,是通过Access-Control-Allow-Origin来判断;但是对于非简单请求,浏览器并不是直接请求所需要资源,而是先发出一个预检请求,预检请求通过后才会对所需资源进行请求。

非简单请求预检请求

这里涉及到的简单请求和非简单请求的概念,那么简单请求和非简单请求有什么区别呢?MDN 对非简单请求进行了定义,满足下列条件之一,即为非简单请求:

  1. 使用了下列 HTTP 方法:PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH;
  2. 使用了除以下首部之外的其他首部:Accept、Accept-Language、Content-Language、Content-Type;
  3. Content-Type首部的值不属于下列其中一个: application/x-www-form-urlencoded、 multipart/form-data、 text/plain;
  4. 请求中的 XMLHttpRequestUpload 对象注册了任意多个事件监听器;
  5. 请求中使用了ReadableStream对象

简单来说,除了我们平时使用最多的 GET 和 POST 方法,以及最常使用的 Accept、Accept-Language、Content-Language 和 类型为 application/x-www-form-urlencoded、 multipart/form-data、 text/plain 的 Content-Type 请求头,其他基本都是非简单请求。对于这些非简单请求,浏览器会发出两个请求,第一个为 OPTIONS 预检请求,预检请求的响应检查通过后才会发出对资源的请求。

但是在生产环境下,如果发送非简单请求,每次两个请求会增加响应时间,为此,W3C标准增加了另外一个响应头Access-Control-Max-Age[啊可谁斯],该参数表明了对于非简单请求的预检请求浏览器的缓存时间,在缓存有效期内,非简单请求可以不发送预检请求。另外,可以在服务端设置接收到的方法是OPTIONS时,直接返回200,这也可以加快响应。

3.3 设置 Access-Control-Allow-Origin: * 就行吗

当我们需要发送cookie的请求时,Access-Control-Allow-Origin直接设置为*是无法通过浏览器的检查的,此时,该响应头的值必须与发请求时的域完全一致才行。另外,还需要设置 Access-Control-Allow-Credentials 响应头为true,表示支持cookie的跨域请求。

图片来源

请求和响应参数详解

3.4 CORS请求头和响应头详解

请求头:

  1. Origin:浏览器发出 Ajax 跨域请求之前会添加此头部,值为发送请求的域;
  2. Access-Control-Request-Method:使用了除 GET、POST 请求方法之外的方法,浏览器会添加此头部,值为当前请求方法;
  3. Access-Control-Request-Headers:使用了自定义头部或除了Accept、Accept-Language、Content-Language、Content-Type 之外的头部,浏览器会添加此头部,值为当前的请求方法;

响应头:

  1. Access-Control-Allow-Origin: 表示服务端允许哪些域请求资源;
  2. Access-Control-Allow-Methods: 当客户端包含 Access-Control-Request-Method 请求头时,服务端需要响应该头部,值通常由 Reauest 的 header 中 Access-Control-Request-Method 取得;
  3. Access-Control-Allow-Headers: 当客户端包含 Access-Control-Request-Headers 请求头时,服务端需要响应该头部,值通常由 Reauest 的 header 中 Access-Control-Request-Headers 取得;
  4. Access-Control-Expose-Headers: 指出客户端通过 XHR 对象的 getResponseHeaders 方法可以获取的响应头有哪些;
  5. Access-Control-Allow-Credentials: 允许带 cookie 的跨域请求;
  6. Access-Control-Max-Age: 预检请求的缓存时间

3.5 java如何实现CORS

主要思想是设置响应头

web.xml配置:

  <filter>
      <filter-name>CorsFilter</filter-name>
      <filter-class>com.springmvc.common.filter.CORSFilter</filter-class>
  </filter>
  <filter-mapping>
      <filter-name>CorsFilter</filter-name>
      <url-pattern>/*</url-pattern>
  </filter-mapping>
  <filter>

拦截器配置:

public class CORSFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Token");
        response.setHeader("Access-Control-Allow-Credentials","true");
        chain.doFilter(req, res);
    }
    public void init(FilterConfig filterConfig) {
    }
    public void destroy() {
    }
}

4. nginx解决跨域问题

  • 首先明确一个概念,前端项目,后端项目,nginx这是三个server项目,他们之间相互交换数据。
  • 三个项目都有自己的ip:port组合,哪怕是在同一台服务器上启动这三个server,他们的port也是可能不同的。
  • 同源策略只存在于浏览器,nginx访问后端项目不存在跨域问题。
  • 前端项目,无论访问nginx还是访问后端项目,都存在跨域问题。

使用nginx解决跨域问题

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,290评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,107评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,872评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,415评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,453评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,784评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,927评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,691评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,137评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,472评论 2 326
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,622评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,289评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,887评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,741评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,316评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,490评论 2 348

推荐阅读更多精彩内容