Skip to content

Instantly share code, notes, and snippets.

@pauloricardomg
Last active November 25, 2024 15:33
Show Gist options
  • Save pauloricardomg/7084524 to your computer and use it in GitHub Desktop.
Save pauloricardomg/7084524 to your computer and use it in GitHub Desktop.
Nginx configuration for CORS-enabled HTTPS proxy with origin white-list defined by a simple regex
#
# Acts as a nginx HTTPS proxy server
# enabling CORS only to domains matched by regex
# /https?://.*\.mckinsey\.com(:[0-9]+)?)/
#
# Based on:
# * http://blog.themillhousegroup.com/2013/05/nginx-as-cors-enabled-https-proxy.html
# * http://enable-cors.org/server_nginx.html
#
server {
listen 443 default_server ssl;
server_name localhost;
# Fake certs - fine for development purposes :-)
ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
ssl_session_timeout 5m;
location / {
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Nginx doesn't support nested If statements, so we
# concatenate compound conditions on the $cors variable
# and process later
# If request comes from allowed subdomain
# (*.mckinsey.com) then we enable CORS
if ($http_origin ~* (https?://.*\.mckinsey\.com(:[0-9]+)?$)) {
set $cors "1";
}
# OPTIONS indicates a CORS pre-flight request
if ($request_method = 'OPTIONS') {
set $cors "${cors}o";
}
# Append CORS headers to any request from
# allowed CORS domain, except OPTIONS
if ($cors = "1") {
more_set_headers 'Access-Control-Allow-Origin: $http_origin';
more_set_headers 'Access-Control-Allow-Credentials: true';
proxy_pass http://serverIP:serverPort;
}
# OPTIONS (pre-flight) request from allowed
# CORS domain. return response directly
if ($cors = "1o") {
more_set_headers 'Access-Control-Allow-Origin: $http_origin';
more_set_headers 'Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE';
more_set_headers 'Access-Control-Allow-Credentials: true';
more_set_headers 'Access-Control-Allow-Headers: Origin,Content-Type,Accept';
add_header Content-Length 0;
add_header Content-Type text/plain;
return 204;
}
# Requests from non-allowed CORS domains
proxy_pass http://serverIP:serverPort;
}
}
@ochko
Copy link

ochko commented Mar 31, 2015

Thanks 🙇

@meglio
Copy link

meglio commented Mar 18, 2016

Thank you!
What is this piece for in the regex?

(:[0-9]+)?

@meglio
Copy link

meglio commented Mar 18, 2016

Another question: why are you using more_set_headers instead of add_header with "always" option? Any special reason for that, or was it jut not available at the time when you created this gist?

@studious
Copy link

(:[0-9]+)?
That covers an optional port in the url

@boltgolt
Copy link

I believe https://badsite.com/?q=sub.mckinsey.com will also match the $http_origin regex check, might be an security issue.

@plrunner
Copy link

Good work, really, thank you.

@cchang62
Copy link

Thanks for sharing.

@genomics-geek
Copy link

Does anyone know how to get add_header on RHEL7? Seems like I can't install the nginx extras needed for this to work

@gantaa
Copy link

gantaa commented Apr 4, 2017

Here is the regex that does NOT match badsite.com security flaw proposed by @boltgolt, but still matches desired domains:

https?:\/\/.[^?]*\.mckinsey\.com(:[0-9]+)?$

@gopal-g
Copy link

gopal-g commented Aug 15, 2017

I am running nginix 1.11.9 and i get the error : unknown directive more_set_headers, I am actually working on vagrant environment with laravel homestead platform hence i am also not sure if this configuration change needs to be updated every time i reload the vagrant. this is my first project on vagrant/homestead.

#Update

I ran sudo apt-get install nginx-extras
restarted nginx - its working just fine

and i even rebooted the vagrant to see if i will lose the changes luckily i didn't thank you very much for this. I am using this script to allow CORS for a angular app satellizer as front-end client with laravel as backend just in case any one is wondering if they can use it for the one of these :) Thank you.

@fkoksal
Copy link

fkoksal commented Sep 27, 2017

Here is the regex that worked for me:
https?:\/\/(.[^?]*\.)?mckinsey\.com(:[0-9]+)?$

  • matches both http and https
  • matches with or without subdomains
  • does not match badsite.com

@ZeusMode
Copy link

ZeusMode commented Sep 29, 2017

for those who are having problems with more_set_headers, you should use add_header.

PS: add_header need 2 params
add_header 'Access-Control-Allow-Credentials' 'true';

@anastasiosyal
Copy link

anastasiosyal commented Mar 9, 2018

Security by regex, will always be weak. Here's another expression that will bypass the 'fixed' version of the regex:
https://badsite.com/#sub.mckinsey.com
There's probably more attack vectors even if you did expand the regex to include the hash exclusion as below
https?:\/\/(.[^?#]*\.)?mckinsey\.com(:[0-9]+)?$

@cholnhial
Copy link

Thank you so much, this was helpful.

@neskhodovskiy
Copy link

neskhodovskiy commented Aug 31, 2018

@anastasiosyal you are right. The most secure regex will at least look something like

https?:\/\/([a-z0-9-]+\.)*mckinsey\.com(:[0-9]+)?$

Test on regex101

Since hostname parts cannot contain anything except alphanumeric characters and dash RFC 952.

@opsarno
Copy link

opsarno commented Nov 9, 2018

Why don't we define $http_origin ?
Access nginx website https://nginx.org/en/docs/varindex.html ,I don't see this variable.

@opsarno
Copy link

opsarno commented Nov 13, 2018

If use https request, the $http_origin it's invalid.

@julioaze
Copy link

Hey there. Where should I use this code? Please

@cvbuelow
Copy link

cvbuelow commented Jan 5, 2019

Not sure why you people are concerned about the regex security when using $http_origin. This variable will not include any path info so you don't have to worry about ? and #.
Ref:
https://nginx.org/en/docs/http/ngx_http_core_module.html#var_http_
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin

@iki
Copy link

iki commented Sep 15, 2019

Thanks for inspiration. Here's what we use with added exposed headers: https://gist.github.com/iki/1247cd182acd1aa3ee4876acb7263def

@libmw
Copy link

libmw commented Aug 12, 2021

Not sure why you people are concerned about the regex security when using $http_origin. This variable will not include any path info so you don't have to worry about ? and #.
Ref:
https://nginx.org/en/docs/http/ngx_http_core_module.html#var_http_
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin

Yeah,I think so!

@feelchi1star
Copy link

Thank you Very very Much For Posting this solution. I had been Battling with this for 2 months. But in less than 3min, i was able to fix it with the solution you provided.

@kasir-barati
Copy link

Hey there. Where should I use this code? Please

@julioaze in your /etc/nginx/sites-available/default or somewhere with similar functionality.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment