My app runs on Google Compute Engine. Nginx used as a proxy server. Nginx was configured to use SSL. Below is the content of /etc/nginx/sites-available/default:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name mywebapp.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
include snippets/ssl-mywebapp.com.conf;
include snippets/ssl-params.conf;
root /home/me/MyWebApp/wwwroot;
location /.well-known/ {
}
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
In Startup.cs I have:
app.UseGoogleAuthentication(new GoogleOptions()
{
ClientId = Configuration["Authentication:Google:ClientId"],
ClientSecret = Configuration["Authentication:Google:ClientSecret"],
});
Now in Google Cloud Platform I need to specify Authorized redirect URIs. If I enter the following, my web app works as expected:
http://mywebapp.com/signin-google
But, it won't work if https
is used; browser displays the following error:
The redirect URI in the request, http://mywebapp.com/signin-google, does
not match the ones authorized for the OAuth client.
In this case, is it safe to use http as authorized redirect uri? What configuration do I need if I want it to be https?
This happens because your application which is running behind a reverse proxy server doesn't have any idea that originally request came over HTTPS.
SSL/TLS Termination Proxy
The configuration of the reverse proxy described in the question is called SSL/TLS Termination reverse proxy. That means that secure traffic is established between a client and a proxy server. The proxy server decrypts a request and then forwards it to an application over HTTP protocol.
The issue with this configuration is that an application behind it is not aware that client sent request over HTTPS. So when it comes to redirect to itself it uses
HttpContext.Request.Scheme
,HttpContext.Request.Host
andHttpContext.Request.Port
to build a valid URL for redirect.X-Forwarded-* HTTP Headers
This is where
X-Forwarded-*
headers come into play. To let the application know that request is originally coming through a proxy server over HTTPS we have to configure the proxy server to setX-Forwarded-For
andX-Forwarded-Proto
HTTP headers.OK, now if we get back to ASP.NET Core application and take a look at incoming HTTP request we will see both
X-Forwarded-*
headers set, however a redirect URL still uses HTTP scheme.Forwarded Headers Middleware
Basically this middleware overrides
HttpContext.Request.Scheme
andHttpContext.Connection.RemoteIpAddress
to values which were provided byX-Forwarded-Proto
andX-Forwarded-For
headers appropriately. To make it happen let's add it to pipeline by adding the following line somewhere in the beginning of theStartup.Configure()
method.This should eventually make your application construct valid URLs with HTTPS scheme.
My Story
The code above looks different to what Microsoft suggests. If we take a look in documentation their code looks a bit shorter:
However this didn't work for me. Also according to the comments under this issue I'm not alone.
I have a nginx set up as reverse proxy for ASP.NET Core application running in Docker container. It became more complicated after I put everything behind Amazon Load Balancer (ELB).
I followed advice from the documentation first, but it didn't work for me. I have got the following warning in my app:
Then I looked at my
X-Forwarded-*
headers and realized that they had different length.X-Forwarded-For
header was containing 2 records (comma separated IP addresses), whileX-Forwarded-Proto
only one recordhttps
. This is how I came up to setting the propertyRequireHeaderSymmetry
tofalse
.Well, I got rid of 'Parameter count...' warning message, but immediately after that I faced another odd debug message:
After looking into the source code of ForwardedHeadersMiddleware I have finally figured out that I have to either clean up both
KnownNetworks
andKnownProxies
collections of theForwardedHeadersOptions
or add my docker network172.17.0.1/16
to the list of known networks. Right after that I have finally got it working.PS: For those who sets up a SSL/TLS termination on load balancer (e.g. Amazon Load Balancer or ELB) DON'T set header
X-Forwarded-Proto
in nginx configuration. This will override correcthttps
value which came from load balance to thehttp
scheme and redirect url will be wrong. I have not found yet how to just append scheme used in nginx to the header instead of overriding it.