1

I have added the following server declaration so that all www. prefixed requests should redirect to the non-www url.

server {
  server_name www.spottingquotes.ca;
  return 301 https://spottingquotes.ca$request_uri;
}

This works great with the exception of the url https://www.spottingquotes.ca which throws a certificate error because the cert does not have the www. prefix. You can test this by going into incognito mode and entering the url "https://www.spottingquotes.ca", the site will render, then enter the same url and a cert error is thrown.

My question is, why does this server declaration catch the request properly on the first request but not the subsequent requests. Furthermore, how do I fix this?

A better test is to use the command line which always fails on that url.

I've built this little shell script for testing the various urls which always fails on the https://www.spottingquotes.ca request:

#!/bin/sh
url=spottingquotes.ca
target=https://$url
echo "---> Target:  $target"
curl -I $target
echo "******************************************************************************"

target=https://www.$url
echo "---> Target:  $target"
curl -I $target
echo "******************************************************************************"

target=http://$url
echo "---> Target:  $target"
curl -I $target
echo "******************************************************************************"

target=http://www.$url
echo "---> Target:  $target"
curl -I $target
echo "******************************************************************************"

target=$url
echo "---> Target:  $target"
curl -I $target
echo "******************************************************************************"

Can someone guide me in the right direction or explain why my server declaration is not stripping the https://www. variant properly?

Thanks.

EDIT Here is a sample of the scripts results:

./curl-url.sh 
---> Target:  https://spottingquotes.ca
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Mon, 28 Jan 2019 23:40:15 GMT
Content-Type: text/html; charset=utf-8
Connection: keep-alive
Status: 200 OK
Cache-Control: max-age=0, private, must-revalidate
Strict-Transport-Security: max-age=604800
Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
X-Permitted-Cross-Domain-Policies: none
X-XSS-Protection: 1; mode=block
X-Request-Id: 41d5365b-161d-4f1e-b117-552849a1a196
X-Download-Options: noopen
ETag: W/"ceabfe116d120b23bf65d7f839911ae6"
X-Runtime: 0.012416
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Content-Security-Policy: default-src 'self'; base-uri 'self'; block-all-mixed-content; child-src 'self' *.google.com *.stripe.com; connect-src 'self' *.stripe.com; font-src 'self' data: *.cloudflare.com *.gstatic.com; frame-ancestors 'none'; img-src 'self' data: *.google-analytics.com *.cloudflare.com *.gstatic.com *.googleapis.com *.stripe.com *.s3-us-east-2.amazonaws.com; manifest-src 'self'; media-src 'self'; object-src 'none'; sandbox allow-scripts allow-same-origin allow-forms allow-popups allow-modals; script-src 'self' 'unsafe-inline' 'unsafe-eval' *.googleapis.com *.cloudflare.com *.google-analytics.com *.bootstrapcdn.com *.google.com *.gstatic.com *.stripe.com *.atlassian.net *.googletagmanager.com; style-src 'self' 'unsafe-inline' *.googleapis.com *.cloudflare.com *.bootstrapcdn.com; worker-src 'self'; report-uri 'self'
Set-Cookie: Quotr_session=UVBYeGQ0QXBnY2VWMGZvb3RZUHI5bEVuS3ZFT1hYN2pNUlppZHFuZWRoU3RUSC9wdHdMM3l4UGQ4aHdxb1VYVU9yUGVlQjhVRlhXb0h5Y1Y1UWluV0MwbENkcXYydml5TkRjVWVjRG1NODZBa3dyRW94T0ZISWVjZXlkTWpHcDdlSVV2cUtHRy9vbXppNHJndlZ3ZXBBPT0tLUFKc09NWElBc0o2Y1dEbTVndStPbXc9PQ%3D%3D--e382dcfbc60ccb44d155e9f317c553d8a47df2f7; path=/; secure; HttpOnly; SameSite=Lax
X-Powered-By: Phusion Passenger 5.3.0
Strict-Transport-Security: max-age=15768000; includeSubDomains

******************************************************************************
---> Target:  https://www.spottingquotes.ca
curl: (51) SSL: certificate subject name (spottingquotes.ca) does not match target host name 'www.spottingquotes.ca'
******************************************************************************
---> Target:  http://spottingquotes.ca
HTTP/1.1 301 Moved Permanently
Server: nginx/1.10.2
Date: Mon, 28 Jan 2019 23:40:15 GMT
Content-Type: text/html
Content-Length: 185
Connection: keep-alive
Location: https://spottingquotes.ca/

******************************************************************************
---> Target:  http://www.spottingquotes.ca
HTTP/1.1 301 Moved Permanently
Server: nginx/1.10.2
Date: Mon, 28 Jan 2019 23:40:15 GMT
Content-Type: text/html
Content-Length: 185
Connection: keep-alive
Location: https://spottingquotes.ca/

******************************************************************************
---> Target:  spottingquotes.ca
HTTP/1.1 301 Moved Permanently
Server: nginx/1.10.2
Date: Mon, 28 Jan 2019 23:40:15 GMT
Content-Type: text/html
Content-Length: 185
Connection: keep-alive
Location: https://spottingquotes.ca/

******************************************************************************

EDIT EDIT I should mention that we are always redirecting http traffic to https via this server declaration:

server {
  listen 80 default_server;
  listen [::]:80 default_server;

  # Redirect all HTTP requests to HTTPS with a 301 Moved Permanently response.
  return 301 https://spottingquotes.ca$request_uri;
}
gwnp
  • 1,127
  • 1
  • 10
  • 35

3 Answers3

0

Not the best answer, but this seems fishy. You have 2 headers on strict-transport-security. First one doesn't include subdomain, second does. Can you try removing the one without it

tkchk ~ $ curl -I https://spottingquotes.ca/
HTTP/2 200
server: nginx/1.10.2
date: Tue, 29 Jan 2019 00:41:12 GMT
content-type: text/html; charset=utf-8
status: 200 OK
cache-control: max-age=0, private, must-revalidate
strict-transport-security: max-age=604800
referrer-policy: origin-when-cross-origin, strict-origin-when-cross-origin
x-permitted-cross-domain-policies: none
x-xss-protection: 1; mode=block
x-request-id: cf52a3fc-2cee-4f22-986e-70b8d04fd4b0
x-download-options: noopen
etag: W/"7c3640b87c82ac5887927e1dd88ac818"
x-runtime: 0.012091
x-frame-options: DENY
x-content-type-options: nosniff
content-security-policy: default-src 'self'; base-uri 'self'; block-all-mixed-content; child-src 'self' *.google.com *.stripe.com; connect-src 'self' *.stripe.com; font-src 'self' data: *.cloudflare.com *.gstatic.com; frame-ancestors 'none'; img-src 'self' data: *.google-analytics.com *.cloudflare.com *.gstatic.com *.googleapis.com *.stripe.com *.s3-us-east-2.amazonaws.com; manifest-src 'self'; media-src 'self'; object-src 'none'; sandbox allow-scripts allow-same-origin allow-forms allow-popups allow-modals; script-src 'self' 'unsafe-inline' 'unsafe-eval' *.googleapis.com *.cloudflare.com *.google-analytics.com *.bootstrapcdn.com *.google.com *.gstatic.com *.stripe.com *.atlassian.net *.googletagmanager.com; style-src 'self' 'unsafe-inline' *.googleapis.com *.cloudflare.com *.bootstrapcdn.com; worker-src 'self'; report-uri 'self'
set-cookie: Quotr_session=QzRGRjNSRTE1cUlYd2t0ajh6Tk84Q2c2cGpKRVQ0UnFpWjFYSkdZWUR5WEI2WmxyQUNJOFNRMWZWK2xiVjhoVVFQM1BrNmVUU0JuSkMvejErbnh0MjBCOXJ0L2VKZ2V1Y0xwbGU5dXRKRGxqR2Y1bk1FMndjNkdnRC93M3l2ZWs0VFRoZkxBL0ZmMGFqS25NYytjYlN3PT0tLUkycjc0UUhoSXQ1bUZPZ2NESzE5RkE9PQ%3D%3D--fb5840d05440015a608f0e25c6b26ec028bbfdae; path=/; secure; HttpOnly; SameSite=Lax
x-powered-by: Phusion Passenger 5.3.0
strict-transport-security: max-age=15768000; includeSubDomains

This article has more info

https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/

  • Thanks for pointing this out, it was being added in nginx and the application itself. I have corrected that issue but the original problem persists. – gwnp Jan 29 '19 at 04:09
0

why does this server declaration catch the request properly on the first request but not the subsequent requests.

I think this has nothing to do with the server, but a default behavior for WebKit-based browsers. If you'll look at the developers console, you'll see following message (taken from Chrome 71, may be different for Safari or other):

Redirecting navigation www.spottingquotes.ca -> spottingquotes.ca because the server presented a certificate valid for spottingquotes.ca but not for www.spottingquotes.ca. To disable such redirects launch Chrome with the following flag: --disable-features=SSLCommonNameMismatchHandling

I don't know why such a redirect doesn't occur for second time, like Microsoft used to say in their KB articles, "this behaviour is by design" :)

In Gecko-based browsers like Firefox no redirects occurs and it throws a security warning immediately.

how do I fix this?

I think the only way to do it is to get a cert for two domain names. There should be no problem to do this with Letsencrypt. If you have access to DNS for this domain, you can even get a wildcard certificate.

Ivan Shatsky
  • 13,267
  • 2
  • 21
  • 37
0

The problem ended up being that I didn't have the ssl cert for the www.spottingquotes.ca domain setup. I needed to setup a server block like so:

server {
  listen *:443 ssl;
  server_name www.spottingquotes.ca;
  # certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
  ssl_certificate /etc/letsencrypt/live/www.spottingquotes.ca/fullchain.pem; # managed by Certbot
  ssl_certificate_key /etc/letsencrypt/live/www.spottingquotes.ca/privkey.pem; # managed by Certbot
  ssl_session_timeout 1d;
  ssl_session_cache shared:SSL:50m;
  ssl_session_tickets off;

  return 301 https://spottingquotes.ca$request_uri;
}

Now running the curl script shows every url redirects properly.

gwnp
  • 1,127
  • 1
  • 10
  • 35