Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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;
}
}
@marcwebbie

This comment has been minimized.

Copy link

@marcwebbie marcwebbie commented Oct 21, 2013

Thank you for sharing.

@ochko

This comment has been minimized.

Copy link

@ochko ochko commented Mar 31, 2015

Thanks 🙇

@meglio

This comment has been minimized.

Copy link

@meglio meglio commented Mar 18, 2016

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

(:[0-9]+)?
@meglio

This comment has been minimized.

Copy link

@meglio 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

This comment has been minimized.

Copy link

@studious studious commented Mar 30, 2016

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

@boltgolt

This comment has been minimized.

Copy link

@boltgolt boltgolt commented Nov 19, 2016

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

@plrunner

This comment has been minimized.

Copy link

@plrunner plrunner commented Nov 24, 2016

Good work, really, thank you.

@cchang62

This comment has been minimized.

Copy link

@cchang62 cchang62 commented Jan 25, 2017

Thanks for sharing.

@genomics-geek

This comment has been minimized.

Copy link

@genomics-geek genomics-geek commented Feb 27, 2017

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

This comment has been minimized.

Copy link

@gantaa 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

This comment has been minimized.

Copy link

@gopal-g 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

This comment has been minimized.

Copy link

@fkoksal 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

This comment has been minimized.

Copy link

@ZeusMode 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

This comment has been minimized.

Copy link

@anastasiosyal 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

This comment has been minimized.

Copy link

@cholnhial cholnhial commented Jun 25, 2018

Thank you so much, this was helpful.

@neskhodovskiy

This comment has been minimized.

Copy link

@neskhodovskiy 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

This comment has been minimized.

Copy link

@opsarno 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

This comment has been minimized.

Copy link

@opsarno opsarno commented Nov 13, 2018

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

@julioaze

This comment has been minimized.

Copy link

@julioaze julioaze commented Nov 30, 2018

Hey there. Where should I use this code? Please

@cvbuelow

This comment has been minimized.

Copy link

@cvbuelow 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

This comment has been minimized.

Copy link

@iki iki commented Sep 15, 2019

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.