Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to allow access via CORS to multiple domains within nginx

Tags:

cors

nginx

I was having some issues getting SVGs to load on my website if you were viewing website.com instead of www.website.com. The website is on an nginx server, so I added this, and it solved the issue:

location / {
  add_header Access-Control-Allow-Origin "*"; 
}

However, based off what i've read, it seems like this is causes a security problem? Is there a way to only specify www.website.com and website.com instead of *? I ask because I came across this in PHP and it seems like what I need but for nginx:

header('Access-Control-Allow-Origin: http://www.website.com');
header('Access-Control-Allow-Origin: http://website.com');
like image 763
Shonna Avatar asked Apr 12 '16 19:04

Shonna


2 Answers

The W3 spec on Access-Control-Allow-Origin explains that multiple origins can be specified by a space-separated list. In practice, though, this is unlikely to be interpreted correctly by current implementations in browsers (eg fails for Firefox 45 at time of writing); summed up by this comment.

To implement what you need, then the following nginx snippet will check the incoming Origin header and adjust the response accordingly:

location / {
    if ($http_origin ~* "^https?://(website.com|www.website.com)$") {
        add_header Access-Control-Allow-Origin "$http_origin";
    }
}

Add more domains into the regular expression as required; the s? can be removed if you want to solely support http://.

For note, if you're including SVGs directly on a web page via HTML (eg <img src="http://example.com/img.svg>), then CORS and Access-Control-Allow-Origin aren't required. If you're using the crossorigin attribute for your images (such as CORS Enabled Images), or loading via JS etc then the above is needed.


Original answer to adding multiple headers with the same name in nginx (CORS references removed as they were incorrect):

You can use add_header multiple times in a given block:

location / {
  add_header Header-Name "value"; 
  add_header Header-Name "value2"; 
}

and your response will contain:

Header-Name: value
Header-Name: value2

add_header can also feature variables and note that you might want to add the always parameter (see http://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header) if you want headers to be added to all response codes, including errors.

like image 71
davidjb Avatar answered Oct 01 '22 04:10

davidjb


Here is a solution that uses map.

This setup allows you to make requests to any subdomain and any port on my-domain.com.

map $http_origin $allow_origin {
    ~^https?://(.*\.)?my-domain.com(:\d+)?$ $http_origin;
    # NGINX won't set empty string headers, so if no match, header is unset.
    default "";
}

server {
    listen 80 default_server;
    server_name _;
    add_header 'Access-Control-Allow-Origin' $allow_origin;
    # ...
}

http://nginx.org/en/docs/http/ngx_http_map_module.html

There are some unexpected things that occur when using if inside location blocks in NGINX. It's not recommended. https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/ and https://agentzh.blogspot.com/2011/03/how-nginx-location-if-works.html

like image 34
Eric Ihli Avatar answered Oct 01 '22 05:10

Eric Ihli