HSTS header in .htaccess set up, but not working - .htaccess

I set the lines below on .htaccess file for many websites I developed :
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
<if "%{HTTPS} == 'on'">
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
</if>
I also successfully added the concerned domains on https://hstspreload.org/
Unfortunately, all tests I've done (Chrome development tools, https://securityheaders.com) in order to check if HSTS was well operational failed.
All of the domains have a valid SSL certificate installed, for all domains and subdomains.
I also tried to set headers with PHP, same results.
Does anyone know why, and how to make HSTS effective to pass the test ?
Thanks for your help

Related

How do I stop the rewrite to force https from affecting all the subdomains

I have this rule to switch all http connections to https. Edited to show the whole file
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www\.example\.kiwi$ [OR]
RewriteCond %{HTTP_HOST} ^example\.nz$ [OR]
RewriteCond %{HTTP_HOST} ^www\.example\.nz$
RewriteRule ^/?$ "https\:\/\/example\.kiwi\/$1" [R=301,L]
RewriteCond %{HTTP_HOST} ^example\.app$ [OR]
RewriteCond %{HTTP_HOST} ^www\.example\.app$
RewriteRule ^/?$ "https\:\/\/example\.kiwi\/$1" [R=301,L]
RewriteCond %{HTTP_HOST} ^example\.online$ [OR]
RewriteCond %{HTTP_HOST} ^www\.example\.online$
RewriteRule ^/?$ "https\:\/\/example\.kiwi\/$1" [R=301,L]
RewriteCond %{HTTP_HOST} ^example\.software$ [OR]
RewriteCond %{HTTP_HOST} ^www\.example\.software$
RewriteRule ^/?$ "https\:\/\/example\.kiwi\/$1" [R=301,L]
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301,NE]
Header always set Content-Security-Policy "upgrade-insecure-requests;"
Header always setifempty Strict-Transport-Security "max-age=31536000" env=HTTPS
Header append X-Frame-Options: "SAMEORIGIN"
Unfortunately it affects things like mail.domain.com (and others). How do I stop any/all subdomains from being upgraded ?
Assuming you only want to redirect the www subdomain and the domain apex to HTTPS then you can check the Host header in a RewriteCond directive.
For example:
RewriteCond %{HTTP_HOST} ^(www\.)?example\.com [NC]
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301,NE]
The above will only redirect www.example.com or example.com.
I've removed the capturing group in the RewriteRule pattern (ie ^(.*)$) since it's not being used here.
Test with a 302 (temporary) redirect to avoid caching issues.
You will need to clear your browser cache before testing.
Also consider canonicalising the hostname (www vs non-www) in the redirect also.
Header always set Content-Security-Policy "upgrade-insecure-requests;"
However, since not everything is now HTTPS, if you are loading resources from the subdomains over HTTP then this header should be sent conditionally, based on whether the request was over HTTPS to begin with.
For example, on Apache 2.4.10+ you can use Apache expression syntax in the Header directive:
Header always set Content-Security-Policy "upgrade-insecure-requests;" "expr=%{HTTPS} == 'on'"
UPDATE:
I want different suffixes to work such as example.software and example.app, so should I replace the ".com" with ".?"
You could simply remove the TLD in the regex in the first condition. For example:
RewriteCond %{HTTP_HOST} ^(www\.)?example\. [NC]
This will now match example.com, example.software, www.example.app etc. But it will fail if you happen to have a subdomain the same name as the domain itself (eg. example.example.com) - but that should be avoided.
I have edited the post to show my whole file, in case there are side-effects. I have a number of domains that are all being redirected for the moment while the website is getting constructed.
This doesn't affect the HTTP to HTTPS redirect. These directives redirect all the other domains to https://example.kiwi - so when these directives are processed the later HTTP to HTTPS redirect is bypassed (not required) anyway.
However, there are a couple of issues with these redirects.
"redirected for the moment" - You imply that these redirects are temporary, but you are using a 301 (permanent) response. This results in the redirect being cached persistently, which can be impossible to undo. If this is temporary then it should be a 302 (temporary) redirect.
^/?$ - You are only redirecting requests for the document root (ie. the homepage). A request for example.nz/foo will not be redirected. This further looks like an error because you are using a $1 backreference in the substitution string, which will consequently always be empty.
These redirect directives could also be greatly simplified. If you are "temporarily" redirecting all other domains to https://example.kiwi/<url> then you could do it with a single rule like this instead:
RewriteCond %{HTTP_HOST} !=example.kiwi
RewriteRule ^ https://example.kiwi%{REQUEST_URI} [R=302,L]
Where !=example.kiwi is a negated exact match string comparison (not a regex). The condition is successful then the Host header does not match example.kiwi.
Aside:
Header always setifempty Strict-Transport-Security "max-age=31536000" env=HTTPS
You shouldn't be implementing HSTS whilst still in development and changing domains. However, you don't appear to be setting an HTTPS env var in the code you have posted, so this is likely being ignored anyway. (?)
NB: env=HTTPS is not checking the server variable of the same name.

WWW Redirection in an HTACCESS File

I have an htaccess file for a React app at https://searchglutenfree.com/. I want it to automatically rewrite https://www.searchglutenfree.com/ to https://searchglutenfree.com/ while keeping all the params during the redirection.
I found this great default htaccess template on GitHub (https://gist.github.com/iheartmedia-matt/253ccb6183fdeaa5619f615f2cb5a58b), and getting the www to redirect is the last thing I need. Anyone know what I need to add and where in the file to get the WWW rewrite?
<ifModule mod_rewrite.c>
#######################################################################
# GENERAL #
#######################################################################
# Make apache follow sym links to files
Options +FollowSymLinks
# If somebody opens a folder, hide all files from the resulting folder list
IndexIgnore */*
#######################################################################
# REWRITING #
#######################################################################
# Enable rewriting
RewriteEngine On
# If its not HTTPS
RewriteCond %{HTTPS} off
# Comment out the RewriteCond above, and uncomment the RewriteCond below if you're using a load balancer (e.g. CloudFlare) for SSL
# RewriteCond %{HTTP:X-Forwarded-Proto} !https
# Redirect to the same URL with https://, ignoring all further rules if this one is in effect
RewriteRule ^(.*) https://%{HTTP_HOST}/$1 [R,L]
# If we get to here, it means we are on https://
# If the file with the specified name in the browser doesn't exist
RewriteCond %{REQUEST_FILENAME} !-f
# and the directory with the specified name in the browser doesn't exist
RewriteCond %{REQUEST_FILENAME} !-d
# and we are not opening the root already (otherwise we get a redirect loop)
RewriteCond %{REQUEST_FILENAME} !\/$
# Rewrite all requests to the root
RewriteRule ^(.*) /
</ifModule>
<IfModule mod_headers.c>
# Do not cache sw.js, required for offline-first updates.
<FilesMatch "sw\.js$">
Header set Cache-Control "private, no-cache, no-store, proxy-revalidate, no-transform"
Header set Pragma "no-cache"
</FilesMatch>
</IfModule>
If you don’t need this to be dynamic regarding the host name, then I would add a Condition that checks if the host name started with www. after the one that checks for %{HTTPS} off, and add the [OR] flag to the former - and then simply hard-code the host name in the substitution URL of the following Rule.
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\.
RewriteRule ^(.*) https://searchglutenfree.com/$1 [R,L]
If you replace everything between the comments # If its not HTTPS and # If we get to here, it means we are on https:// in your .htaccess you had shown above with that, it should work.
In order to set up the desired redirect, www.example.com to example.com or vice versa, you must have an A record for each name.
To redirect users from www to a plain, non-www domain, insert this configuration:
in your .htaccess:
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,L]

Need to redirect to HTTPS using my current htaccess

I want to redirect HTTP and www to https://example.com.
I tried using:
# force HTTPS and www.
RewriteEngine On
RewriteCond %{HTTP_HOST} (?!^www\.)^(.+)$ [OR]
RewriteCond %{HTTPS} off
RewriteRule ^ https://www.%1%{REQUEST_URI} [R=301,L]
But the result is only https://www. - the domain disappeared!
My current .htaccess:
<IfModule mod_rewrite.c>
# REWRITE ENGINE CONFIG
#ExpiresActive On
DirectoryIndex under_construction.html index.html index.php
#Header set Cache-Control "max-age=259200, public"
#ExpiresDefault "access plus 3 days"
#Header unset ETag
#FileETag None
# Expires header for static content
#<FilesMatch "\.(ico|jpg|jpeg|png|gif|js|css|swf|jgz|js.jgz)$">
#Header set Cache-Control "max-age=31536000, public"
#ExpiresDefault "access plus 11 months"
#</FilesMatch>
# Auth for non-public projects
#AuthName "ZEN 2.2 Login"
#AuthType Basic
#AuthUserFile /Applications/MAMP/htdocs/username/.htpasswd
#AuthUserFile F:/wamp/www/username/.htpasswd
#AuthGroupFile /dev/null
#require valid-user
# REWRITE CORE RULES RULES -- PLEASE DON'T MODIFY --
# THESE ARE THE MAIN REWRITES THAT MAKE THE ENTIRE WORLD SPIN
AddDefaultCharset UTF-8
# IF NO IMAGE FOUND
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} \.(gif|jpg|jpeg|png)$
RewriteRule .* resources/static/images/no_image.png [L]
RewriteCond $1 !^(index\.php|resources|robots\.txt)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?page=$1&%{QUERY_STRING} [L,QSA]
RewriteRule ^robots.txt$ resources/static/robots.php [L]
# gZip minified js files
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{REQUEST_FILENAME}.jgz -f
RewriteRule (.*)\.js$ $1\.js.jgz [L]
AddType "text/javascript" .js.jgz
AddEncoding gzip .jgz
# gZip minified css files
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{REQUEST_FILENAME}.jgz -f
RewriteRule (.*)\.css$ $1\.css.jgz [L]
AddType "text/css" .css.jgz
AddEncoding gzip .jgz
</IfModule>
Need some help adding the redirection to HTTPS and non-WWW to the current .htaccess file.
The problem when using code from here -> https://gist.github.com/vielhuber/f2c6bdd1ed9024023fe4
Is that the redirection is broken, and the result is https://www. only, no domain name is showing.
Try:
# force HTTPS and www.
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [OR]
RewriteCond %{HTTPS} !on
RewriteRule ^(.*)$ https://%1%{REQUEST_URI} [R=301,QSA,L]
Some webservers don't create the HTTPS header when http protocol is used. So if HTTPS is not on (is off or null) this condition is true.
# force HTTPS and www.
RewriteEngine On
RewriteCond %{HTTP_HOST} (?!^www\.)^(.+)$ [OR]
RewriteCond %{HTTPS} off
RewriteRule ^ https://www.%1%{REQUEST_URI} [R=301,L]
The problem with this code is, as the preceding comment suggests, it tries to redirect to www, not the domain apex. But it is also fundamentally flawed since the first condition is not always met (when HTTPS is off and www is requested), so the %1 backreference is not always set (so the domain name is omitted from the redirect - as you have found).
If you want a generalised (ie. without explicitly stating the hostname) solution then you would need to do something like the following instead:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\. [OR]
RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)
RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]
The above rule block states... for all requests that are either for the www subdomain OR are for HTTP then redirect to HTTPS, less the www subdomain (if any) at the same URL-path.
The purpose of the 3rd condition - which must always match - is to simply capture the hostname less the www subdomain (if any). This is then referenced using the %1 backreference in the RewriteRule substitution.
NB: Test with a 302 (temporary) redirect first to avoid caching issues.
You will need to clear your browser cache before testing.
UPDATE: it is redirecting to domainname.com:443
That shouldn't be happening with the above directives, unless perhaps the port is explicitly included in the request? (But is that a redirect for http or https?)
You can try changing the 3rd condition to read:
RewriteCond %{HTTP_HOST} ^(?:www\.)?([^:]+)
Or hardcode the canonical hostname, which is arguably preferable and more reliable (without knowing your system). For example:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\. [OR]
RewriteCond %{HTTPS} off
RewriteRule ^ https://example.com%{REQUEST_URI} [R=301,L]
With this hardcoded solution, it cannot possibly redirect to anything other than the canonical URL - regardless of the request or system configuration.
EDIT#1: if I remove the htaccess file completely, the website still redirect to :443 if access from https
To help with debugging, try the following in your .htaccess file and then access https://your-domain.com/. What happens?
RewriteEngine On
RewriteCond %{HTTPS} on
RewriteRule ^ - [F]
If you see a 403 Forbidden response then your web application would seem to be triggering this redirect. If not and you are still redirected then something in the main server config / virtual host would seem to be triggering the redirect.
EDIT#2: Yes, the response when i browse the https is 403 Forbidden.
That would seem to suggest that your web application is triggering this redirect.
And this would seem to be further backed up by the fact that you only seem to get this malformed redirect when requesting a valid URL, ie. one which only the app knows about. For example, https://example.com/contact (a valid page) is redirecting to http://example.com:443/contact (ERROR), but https://example.com/does-not-exist does not redirect (you get an application error / 404).

How to disable HSTS header with HTTP?

I have inserted the following in the .htaccess of my site in order to be admitted to the HSTS preload list:
<ifModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
</ifModule>
The problem is that when I submit my site, I obtain:
Warning: Unnecessary HSTS header over HTTP.
The HTTP page at
http: //fabriziorocca.it sends an HSTS header. This has no effect over
HTTP, and should be removed.
At the moment I use the following in the .htaccess in order to switch from http to https:
RewriteCond %{HTTPS} off
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule .* https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
How can I solve the problem?
Thank you in advance.
Below your redirect rules add the code:
Header always set Strict-Transport-Security "max-age=31536000;
includeSubDomains; preload" env=HTTPS
I added in htaccess works perfectly for me.
RewriteEngine On
RewriteCond %{HTTPS} off
# First rewrite to HTTPS:
# Don't put www. here. If it is already there it will be included, if not
# the subsequent rule will catch it.
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# Now, rewrite any request to the wrong domain to use www.
# [NC] is a case-insensitive match
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule .* https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# Use HTTP Strict Transport Security to force client to use secure connections only
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" "expr=%{HTTPS} == 'on'"
env=HTTPS not works now.
Try with:
<ifModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" "expr=%{HTTPS} == 'on'"
</ifModule>
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule .* https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{HTTPS} off
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
No...
Error: HTTP redirects to www first
http://domain.fr (HTTP) should immediately redirect to https://domain.fr (HTTPS) before adding the www subdomain. Right now, the first redirect is to https://www.domain.fr/. The extra redirect is required to ensure that any browser which supports HSTS will record the HSTS entry for the top level domain, not just the subdomain.

.htaccess not working properly while setting SSL redirects only on certain pages

While looking for an answer for the question above I have encountered this script as a solution(I would like to have my website on http except of a few pages like login, register,manage etc.):
Options +FollowSymLinks -MultiViews
RewriteEngine On
RewriteBase /
# force https for /login.php and /register.php
RewriteCond %{HTTPS} =off
RewriteRule ^(login|register)\.php$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# don't do anything for images/css/js (leave protocol as is)
RewriteRule \.(gif|jpe?g|png|css|js)$ - [NC,L]
# force http for all other URLs
RewriteCond %{HTTPS} =on
RewriteCond %{REQUEST_URI} !^/(login|register)\.php$
RewriteRule .* http://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
This exact example should work on my server, but it works only partially, meaning, it redirects all pages to http, but I am unable to open login.php or register.php. The webbrowser states that these pages include redirect loop and they can't show up. By no means I am not an expert on mode_rewrite or htaccess so I would appreciate any help.
edit:
I have followed the suggestions and run mywebsite with chrome plugin. I discovered that in the page login.php has redirect loop http->https->http etc. (The only other redirection on that page is when the user is already signed, but it doesn't seem ike a couse for this loop). I have tried also different codes for setting SSL and this one works:
# Rewrite Rules for example.com
RewriteEngine On
RewriteBase /
# Turn SSL on for payments
RewriteCond %{HTTPS} off
RewriteCond %{SCRIPT_FILENAME} \/login\.php [NC]
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# Turn SSL off everything but payments
RewriteCond %{HTTPS} on
RewriteCond %{SCRIPT_FILENAME} !\/login\.php [NC]
RewriteRule ^(.*)$ http://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
And this one is working correctly, but it has only one exception for https and I would like to have more of them(around 6). Has someone any idea why the first script is not working? or how to modify the second one in order to have more https websites?
Thanks
I had similar problem, this is what worked for me.
In your httpd.conf, under virtual hosts, make sure you have both:
ServerName domain.com
ServerAlias www.domain.com
BOTH in VirtualHost *:80 AND VirtualHost *:443

Resources