Home > Software engineering >  AWS- subdomain doesn't support HSTS
AWS- subdomain doesn't support HSTS

Time:09-22

I am using Semrush and I have this one notice that is really bothering me and want to get rid of. 1 subdomain doesn't support HSTS for the subdomain: www.domain.com , here is my .htdocs file:

Options -Indexes

<IfModule mod_rewrite.c>
    Options  FollowSymLinks
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php/$1 [L]
    RewriteCond %{HTTPS} !=on
    RewriteCond %{HTTP_USER_AGENT} ^(. )$
    RewriteCond %{SERVER_NAME} ^example\.com$
    RewriteRule .* https://www.%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
    Header add Strict-Transport-Security "max-age=300"
</IfModule>
<IfModule mod_headers.c>
    <If "%{REQUEST_SCHEME} == 'https' || %{HTTP:X-Forwarded-Proto} == 'https'">
        Header always set Strict-Transport-Security "max-age=31536000"
    </If>
</IfModule>

I add this part at the end:

<IfModule mod_headers.c>
        <If "%{REQUEST_SCHEME} == 'https' || %{HTTP:X-Forwarded-Proto} == 'https'">
            Header always set Strict-Transport-Security "max-age=31536000"
        </If>
    </IfModule>

But still nothing, what am I doing wrong?

CodePudding user response:

Have you tried to fix this via DNS record and .vconfig file? For my websites, I have:

  1. DNS A records for main domain (A domain.com 123.123.123.123)
  2. Second DNS A record for www (A www 123.123.123.123)

and then in domain.com.vhost:

<VirtualHost *:80>

    DocumentRoot /var/www/path_to_root

    ServerName domain.com
    ServerAlias domain.com

    RewriteEngine on
    RewriteCond %{HTTPS} off
    RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L,NE]

</VirtualHost>

The rewrite rule forces HTTPS.

If you want to force HTTPS for specific domain, both in .vhost or .htaccess you can use:

RewriteEngine On 
RewriteCond %{HTTP_HOST} ^yourdomain1.com [NC] 
RewriteCond %{HTTPS} off 
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

and for specific folder:

RewriteEngine On 
RewriteCond %{HTTPS} off 
RewriteRule ^(folder1|folder2|folder3) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

Make sure to change the folder references to the actual directory names.

CodePudding user response:

If you're able to route your DNS via Cloudflare (even on their free plans), you'll be able to enable HSTS at the click of a button (including for subdomains). Loads of other benefits for speed and security too which might also help with your SEMRush report

CodePudding user response:

Options -Indexes

<IfModule mod_rewrite.c>
    Options  FollowSymLinks
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php/$1 [L]
    RewriteCond %{HTTPS} !=on
    RewriteCond %{HTTP_USER_AGENT} ^(. )$
    RewriteCond %{SERVER_NAME} ^example\.com$
    RewriteRule .* https://www.%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
    Header add Strict-Transport-Security "max-age=300"
</IfModule>
<IfModule mod_headers.c>
    <If "%{REQUEST_SCHEME} == 'https' || %{HTTP:X-Forwarded-Proto} == 'https'">
        Header always set Strict-Transport-Security "max-age=31536000"
    </If>
</IfModule>

There are a number of issues here that will prevent HSTS from working properly and some additional optimisations that should made.

  1. You are not redirecting http://www.example.com (ie. the www subdomain) to HTTPS. You need to redirect HTTP WWW to HTTPS WWW in order to be HSTS compliant.

  2. You are redirecting http://example.com/ (ie. HTTP non-www) to HTTPS WWW. In order to be HSTS compliant, you need to redirect to HTTPS on the same host first. ie. http://example.com/ to https://example.com/ to https://www.example.com (yes, that's two redirects, but it's also rare and will only occur at most once per user-agent, because of the STS header that is returned).

  3. Your directives are in the wrong order. Your canonical redirects (ie. HTTP to HTTPS and non-www to www) need to be before your front-controller rewrite (the first rule). By placing them after the front-controller they are never going to be processed for anything other than the homepage, directories and static resources. eg. http://example.com/<some-url> will never be redirected by the rules as written. Not sure how you are testing HSTS compliance with SEMrush, but with the directives as written then http://example.com/<some-url> would fail, since it's not redirected.

  4. You should remove the first Header directive - this is in direct conflict with the 2nd (correct) Header directive. The always condition (as used in the second instance) is required in order to set the header on the HTTPS 301 redirect (ie. non-2xx response) from non-www to www.

  5. You should include the includeSubDomains directive on the Strict-Transport-Security header in order to cover the www subdomain when the domain apex is requested. Although, all subdomains will now be implicitly included. Without this, the www subdomain will need to be explicitly requested. (Ok, you are redirecting to www anyway in the next request.)

  6. You don't need the <IfModule> wrappers. These directives are mandatory, they are not optional (which is implied by the presence of these wrappers). Your site will presumably fail if mod_rewrite is not available and you will not be HSTS compliant.

  7. I assume from the earlier HTTP non-www redirect that you are not behind a front-end proxy (or load balancer) that manages your SSL, in which case the check for %{HTTP:X-Forwarded-Proto} in the later <If> expression should be removed. If you are not behind a "proxy" then it would be possible to fake a request to prevent the STS header being sent back (a user should not be able to do this).

    Conversely, if you are behind a "proxy" then the check for %{REQUEST_SCHEME} == 'https' is redundant - but causes no harm. Incidentally, the use of REQUEST_SCHEME assumes you are on Apache 2.4 (which I expect you are), however, if you are still on Apache 2.2 then this check will fail and the STS header will not be set.

So, taking the above points into consideration, your .htaccess file should be written like this:

Options  FollowSymLinks -Indexes

RewriteEngine On

# Redirect HTTP to HTTPS on the same host (requirement of HSTS)
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Redirect non-www to www (HTTPS only)
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Front-controller
RewriteRule ^index\.php/ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php/$1 [L]

<If "%{REQUEST_SCHEME} == 'https'>
    # The "always" condition is required to set the header on the HTTPS redirect
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</If>

Additional notes:

  • I've used HTTP_HOST instead of SERVER_NAME since you need the hostname present on the request. By default SERVER_NAME is the same as HTTP_HOST, but this can vary based on the server config.

  • There is no reason to only apply the canonical redirect when a non-empty User-Agent string is present on the request (a malicious request could suppress the User-Agent string) as you had originally, so I've removed this condition. If anything, you would block such requests.

  • The regex ^ in the RewriteRule pattern is more optimal than .* since it only needs to be successful - it doesn't need to actually match anything since it is not being used later.

  • The additional RewriteRule ^index\.php/ - [L] directive before the "front-controller" is simply an optimisation to prevent rewritten URLs from being unnecessarily passed through the filesystem checks that follow.

  • Related