Multiple CORS origins. Should I use if statement? - NginX
Typically, where you think of using if
with nginx, it is much better to use map
instead.
In this case you would create a map
stating all allowed origins:
map $http_origin $origin_allowed {
default 0;
https://foo.example.com 1;
https://bar.example.com 1;
# ... add more allowed origins here
}
Note that there are no nested if
s. So this won't work:
if ($request_method = 'OPTIONS') {
if ($origin_allowed = 1) {
...
Putting map
in further use and accounting for the fact that add_header
will not be sending anything if the value is empty, you can have something that works:
map $http_origin $origin_allowed {
default 0;
https://foo.example.com 1;
https://bar.example.com 1;
# ... add more allowed origins here
}
map $origin_allowed $origin {
default "";
1 $http_origin;
}
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' $origin;
...
The special $origin
variable will contain one of our allowed origins, or if not matched, will be empty. When add_header
is invoked with empty value, the header won't be sent. Thus it will be sent only for allowed origins.
Related videos on Youtube
Nikolaos Paschos
Updated on September 18, 2022Comments
-
Nikolaos Paschos over 1 year
I have set up an NginX in order to serve some static files from an instance.
The static files are to be used by 3 different domains that I own.
The NginX server is on its own (4th) domain. I want to restrict access to my files and apply a CORS policy.
I have researched as to how this can be achieved and I did manage to do it. In my location block I have tested the following code:
if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' 'http://localhost:3000'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; # # Custom headers and headers various browsers *should* be OK with but aren't # add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; # # Tell client that this pre-flight info is valid for 20 days # add_header 'Access-Control-Max-Age' 1728000; add_header 'Content-Type' 'text/plain; charset=utf-8'; add_header 'Content-Length' 0; return 204; } if ($request_method = 'GET') { add_header 'Access-Control-Allow-Origin' 'http://localhost:3000'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; }
The
http://localhost:3000
is for test purposes. I am currently trying to implement the same logic but only allow 3 specific, predefined domains. I found a possible solution which suggested that I use the following code snippet:if ($http_origin ~* "^https?://example\.domain\.com$" ) { add_header Access-Control-Allow-Origin $http_origin; }
I'm guessing since NginX does not support if-elif-else syntax, that I can get away with it by using 3 if statements. However, I know that if is evil and that I there can be unexpected behavior if some things are not taken into consideration.
I am relatively new to NginX so my question is, is the 3-if approach safe and reliable?
-
Nikolaos Paschos about 5 yearsThat did the trick! I was not aware of the map module, thank you.
-
Toan Nguyen almost 5 yearsThanks Danilla, but when I used it, it says
nginx: [emerg] unknown "origin" variable
:(