2

Currently I use this rule on my WordPress .htaccess file to redirect HTTP to HTTPS:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>

But I found some other rules than the rule I used like this one:

RewriteEngine On
 RewriteCond %{HTTPS} !on
 RewriteCond %{SERVER_PORT} !^443$ 
RewriteCond %{HTTP:X-Forwarded-Proto} !https 
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]

I don't know if these 2 rules do the same job or is there another one which the best one for redirecting from HTTP to HTTPS

OR the rule I used on my .htaccess is perfect enough for doing the redirecting from HTTP to HTTPS?

2

Mix and Match!

They are both pretty similar apart from RewriteCond %{HTTP:X-Forwarded-Proto} !https

This is reverse proxy/load balancer and not fully compatible with every setup, but good to use if you do use one.

It's best to do a mix if you are not sure.

Like This:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https 
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>
  • What if I will use only the one that I am currently using which is the first one, will it do the job of directing from http to https on a perfect way without any issues? – Webdev Oct 10 '18 at 14:03
  • This will work on any: RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] – Invariant Change Oct 10 '18 at 14:04
  • So, yes your first example will work on any. – Invariant Change Oct 10 '18 at 14:06
  • 1
    "It's best to do a mix if you are not sure." - Actually, no. You should only check the HTTP X-Forwarded-Proto request header if you know you are behind a proxy/load balancer. Otherwise, as is the case with your example, you are prone to malicious requests that inject this header to prevent your site from redirecting to HTTPS. The end-user should not be able to manipulate the response in this way. – MrWhite Oct 10 '18 at 14:23
  • I agree, it's best to stick to what you need. However, I've never heard of using both being a security risk. Many people do this. Would you be able to provide any documentation to back this up? I think this type of information would be very useful for anyone reading this if true! – Invariant Change Oct 10 '18 at 14:32
0

As with many flexible programming systems, there are often many different ways to do essentially the same thing. One way isn't necessarily any "better" than another. However, different methods may be required depending on specific requirements or different server configs.

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>

There is nothing wrong with this. If it works for you then go with it. However, you should be aware of what it actually does. Specifically, it redirects to the same URL on the same host. By itself this does not canonicalise the www subdomain - so you might be seeing two redirects for certain non-canonical requests (eg. if WordPress, or another part of your config, canonicalises the www subdomain). Now, this isn't necessarily a bad thing - if you are implementing HSTS then this is actually a requirement. But, if you are not implementing HSTS then you might consider incorporating your canonical www redirect so you only ever get a single redirect.

However, these directives could be "tidied" a bit:

  • You don't need the <IfModule> wrapper, unless you are using these directives on other servers where mod_rewrite might not be available and you have "backup" server-code that redirects HTTP to HTTPS when mod_rewrite is not available. Otherwise, these directives are considered mandatory and the <IfModule> wrapper should be removed.

  • Since you are using WordPress, which already has its own block of mod_rewrite directives, you don't strictly need to repeat the RewriteEngine On directive - even though these directives (presumably) occur before the WP directives. (The last RewriteEngine directive in the .htaccess file wins and controls the entire file/context.)

  • Regex optimisation: ^(.*)$ - you don't need the capturing parentheses in the RewriteRule pattern when you are not making use of the backreference in the substitution (or preceding conditions). In other words, you shopuld change this to: ^.*$ (or simply .* since the anchors are not required either - the regex is greedy by default).

In summary:

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

RewriteCond %{HTTPS} !on
RewriteCond %{SERVER_PORT} !^443$ 
RewriteCond %{HTTP:X-Forwarded-Proto} !https 
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]

Yes, this does "the same job", but in a different way. As @Invariant suggests in his answer, the 3rd condition that checks the X-Forwarded-Proto HTTP request header is required when behind a proxy server (or load balancer) - although this can vary (not all proxies work the same way).

However, these directives are "overkill" and not strictly correct. If you are behind a proxy then the first two conditions are most probably redundant as they likely always evaluate to true. (But you wouldn't need both of these conditions under any circumstances - they essentially do the same thing.) And if you aren't behind a proxy then the 3rd condition (that checks X-Forwarded-Proto) shouldn't be used anyway since it would potentially make your server vulnerable to malicious requests that inject this header, tricking your server into thinking it is already communicating over HTTPS when it is not.

The reason why you see rules like this (and the supposed "advantage") is that it is more "generic" and is more likely to work on different server configs - it can be copy/pasted between sites and stand a better chance of "working". However, as with many "generic" solutions", it introduces redundancy, is less efficient and, in this case, potentially introduces a vulnerability.


When used in .htaccess in the document root of the site then the following two directives result in the same response.

RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]

However, the later will not work if .htaccess is located anywhere else, other than the document root. And nor will it work "properly" outside of a directory context (ie. in the server config).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.