owenzhang的博客

CORS(跨站资源共享)介绍

字数统计: 1.1k阅读时长: 4 min
2017/12/03
loading

起因

有同学在nginx站点配置中加了一行Access-Control-Allow-Origin *,导致微信中业务数据异常,抓包看http头有两个Access-Control-Allow-Origin字段,一个是站点自己的域名,一个是*。 为了实现跨域资源访问,在代码和nginx配置中都加了Access-Control-Allow-Origin字段,但是浏览器有个原则,如果有两个Access-Control-Allow-Origin字段,那么都失效,哪个都不信。最终导致了微信中打开异常。 也引出了CORS。

定义和原理

什么是CORS跨站资源共享?

跨站源资源共享(CORS)是一份浏览器技术的规范,提供了 Web 服务从不同网域传来沙盒脚本的方法,以避开浏览器的同源策略[1],是 JSONP 模式的现代版。与 JSONP 不同,CORS 除了 GET 要求方法以外也支持其他的 HTTP 要求。用 CORS 可以让网页设计师用一般的 XMLHttpRequest,这种方式的错误处理比 JSONP 要来的好。另一方面,JSONP 可以在不支持 CORS 的老旧浏览器上运作。现代的浏览器都支持 CORS[2]。

简单说,就是为了实现跨站访问资源的遍历,同时保护浏览器使用者的安全,提出的一种规范。如何保护的安全,在下一结做介绍。 在html中的图片、css、js等静态引用,和ajax发起的动态请求,都受同源策略影响。如果有跨域,都可以用CORS来实现(也有其他方法,CORS是标准)。 跨域请求主要用于: - 调用XMLHttpRequest或fetchAPI通过跨站点方式访问资源 - 网络字体,例如Bootstrap(通过CSS使用@font-face 跨域调用字体) - 通过canvas标签,绘制图表和视频。

意义

CORS怎么保护安全

客户端

保护用户访问网站的安全。防止用户在A站登录授权后,在访问恶意网站B时,B站在ajax中请求A站,获取A站的信息。

服务端

保护服务器的静态资源、接口数据等,都被自己信任的域名访问,不被其他未授权的网站拉走数据。

实现

客户端

在header中带上Origin字段,标明是跨域请求。如果需要发送带凭证的数据(cookie、Http认证和客户端SSL证明等),将WithCredentials设为true。

1
xhr.withCredentials = true;

如果请求服务器是非简单请求,浏览器会发出一个OPTION请求,和服务器协商信息。

服务器

服务器处理流程: 1 http头部是否有origin字段 2 没有,当成普通请求处理。 3 有,是否method是OPTIONS(preflight) 4 不是OPTIONS(简单请求),返Allow-Origin、Allow-Credentials等,并返回正常内容。 5 是,返回Allow-Headers、Allow-Methods等,内容为空。 nginx参考配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
add_header 'Access-Control-Allow-Origin' 'xxxx';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, DELETE, PUT, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Accept, Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'xxxx';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, DELETE, PUT, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Accept, Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}

注意

1、在代码或nginx一个地方修改,不要在一个http头中有多个Access-Control-Allow-Origin字段,否则会触发“起因”中的问题。 2、修改配置最好在nginx配置中修改,其次在代码中修改,但是一定不要两侧都改,容易造成两侧混乱不容易维护。 3、业务站点不要为了省事给Access-Control-Allow-Origin设置为*,权限太开会有安全隐患。 4、按规范实现的浏览器,会做拦截。如果没有填写Access-Control字段或填写错误,即使服务端返回了全部数据,浏览器也会拦截不给页面。

参考

CORS——跨域请求那些事儿 跨域资源共享 CORS 详解 浏览器和服务器实现跨域(CORS)判定的原理

CATALOG
  1. 1. 起因
  2. 2. 定义和原理
  3. 3. 意义
    1. 3.1. CORS怎么保护安全
      1. 3.1.1. 客户端
      2. 3.1.2. 服务端
  4. 4. 实现
    1. 4.0.1. 客户端
    2. 4.0.2. 服务器
  • 5. 注意
  • 6. 参考