设置带通配符子域名的Access-Control-Allow-Origin实现安全跨域资源共享
在现代互联网技术中,跨域资源共享(CORS:Cross-Origin Resource Sharing)机制使用非常广泛,在兼顾安全性的基础上解决了跨域消息互通,资源共享的问题,目前绝大多数主流的浏览器均支持跨域资源共享(CORS)。然而,按跨域资源共享(CORS)的配置说明,参数Access-Control-Allow-Origin的值要么是通配符(*),要么是指定的固定域名。前者太过开放,不安全,而后者又太死板,不灵活。如果能设置带通配符子域名的Access-Control-Allow-Origin参数那就好了。本文小卓将以NGINX为例设置带通配符子域名的Access-Control-Allow-Origin实现安全跨域资源共享。
什么是跨域资源共享(CORS:Cross-Origin Resource Sharing)?
说起跨域资源共享(CORS:Cross-Origin Resource Sharing)就不得不提到浏览器的同源策略了,即:基于安全的理由,不同域的客户端脚本不能读写对方的资源,先更了解更多同源策略,可以阅读同源策略(Same-origin Policy)。但是实践中有一些场景需要跨域的读写。为了提供满足实际需要,在XMLHttpRequest v2标准下,跨域资源共享(CORS)的策略被提出,它定义了一种浏览器和服务器交互的方式来确定是否允许跨域请求,允许网页从不同的域访问其资源。简而言之,跨域资源共享(CORS:Cross-Origin Resource Sharing)就是为了实现可控的跨域访问而生的。
如何设置跨域资源共享(CORS:CROSS-ORIGIN RESOURCE SHARING)?
正如前文所述,目前绝大多数主流的浏览器均已支持跨域资源共享(CORS),这里的设置指的是服务器端的设置。跨域资源共享(CORS)通过在服务器端设置多个控制参数来完成,这些控制参数在响应浏览器端的请求时,会以header的形势通过响应消息带回带浏览器端,这些参数主要是下面这么四个:
- Access-Control-Allow-Origin: http://foo.example
- Access-Control-Allow-Methods: POST, GET, OPTIONS
- Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
- Access-Control-Max-Age: 86400
这些基本参数的基本设置方式不是本文的重点,需要了解的朋友请阅读《HTTP访问控制:CORS》,这里需要重点指出的是参数Access-Control-Allow-Origin,通过配置Access-Control-Allow-Origin参数可以指定哪些域可以访问你的服务器。你也可以设置简单的通配符(*),但是如果你正允许Cockie共享的话,你不得不一个个指定额外的域名,因为简单的通配符(*)就不行了。所以你会想要能设置像“*.yourdomain.com”这样含有通配符的子域名。按照Access-Control-Allow-Origin设置的说明,Access-Control-Allow-Origin参数只接受下面两种值,含有通配符的子域名不是合法设置:
- Access-Control-Allow-Origin: <origin> | *
也就是要么是指定域名<origin>,要么是简单通配符(*)。就没有第三种了?是的,没有第三种。但我们可以自己动手,通过对配置文件做些修改,用非正常方式达到我们想要的扩展形式,这种扩展形式不仅仅是像“*.yourdomain.com”这样含有通配符的子域名,还可以有更多,完全自己做主,如果自己会写规则的话。
如何设置带通配符子域名的Access-Control-Allow-Origin
上面说到了,规则可以自己做主,但为了简单,也为了满足绝大多数的需求,就以在NGINX下设置成像“*.yourdomain.com”这样含有通配符的子域名作为典型例子。首先找到NGINX服务器的配置文件,通常对站点配置,我们需要修改/etc/nginx/site-enable/your-site-config-file。打开文件后,像下面这样加入一个前置检查,如果匹配的话才动态增加跨域设置。
- server {
- root /path/to/your/stuff;
- index index.html index.htm;
- set $match “”;
- if ($http_origin ~* (.*\.yourdomain.com)) {
- set $match “true”;
- }
- server_name yoursweetdomain.com;
- location / {
- if ($match = “true”) {
- add_header ‘Access-Control-Allow-Origin’ “$http_origin”;
- add_header ‘Access-Control-Allow-Methods’ ‘GET, POST, OPTIONS, DELETE, PUT’;
- add_header ‘Access-Control-Allow-Credentials’ ‘true’;
- add_header ‘Access-Control-Allow-Headers’ ‘User-Agent,Keep-Alive,Content-Type’;
- }
- if ($request_method = OPTIONS) {
- return 204;
- }
- }
- }
OK,这样就能实现带通配符子域名的安全跨域资源共享了,如果你还需要更复杂的规则,那么就制定你的规则,让你的服务器在跨域资源共享上既有便利性又能兼顾安全性。