https redirect for Network Solutions - .htaccess

I am using Network Solutions as a hosting provider with a UNIX hosting package. I need to redirect certain pages to https (login, etc). After going through a lot of testing, I ended up with the following .htaccess entry:
RewriteEngine on
RewriteCond %{SERVER_PORT} !^443$ [OR]
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://[domain_redacted]/$1 [R=301,L]
This resulted in an infinite redirect loop. After discussions with Network Solutions, they told me I needed to 301 redirect (apparently what I was doing is not a 301 redirect ...), so I then tried the following in .htaccess:
Redirect 301 / https://[domain_redacted]/
This, of course, resulted in an infinite loop, as one would expect. Since none of these methods worked, I put the following php script on my server to test https detection through PHP:
<?php
if(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') {
echo 'HTTPS IS ON';
} else {
echo 'HTTPS IS OFF';
}
?>
When requesting this page over both HTTP and HTTPS, the script returns OFF.
So, what other methods exist to detect HTTPS server side in Apache or PHP?

I asked only so I could answer the question, mostly because I couldn't find a solution anywhere.
Background:
The way Network Solutions handles their shared hosting systems, you don't actually connect to a server, you connect to a proxy server (this makes sense). When you perform an https redirect like:
RewriteEngine on
RewriteCond %{SERVER_PORT} !^443$ [OR]
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://[domain_redacted]/$1 [R=301,L]
You do, in fact, redirect the page to HTTPS. However, you are performing your HTTPS transaction with the proxy server, not your hosting server. The proxy server translates your HTTPS connection with it to HTTP over port 80. When attempting to detect this with .htaccess, the server doesn't see HTTPS because the connection between your hosting server and the proxy will always be HTTP on port 80. Because PHP pulls the HTTPS variable from Apache, it will have the identical outcome to detecting HTTP through .htaccess.
Therefore, unless I am mistaken, it is impossible to perform a self-referencing HTTP to HTTPS redirect when on shared hosting from Network Solutions. The request must somehow change (either through a change in the URI or the Query String) in order for the server to detect the change. This, of course, is completely spoofable (e.g. no matter how you change the URI/Query String, one can simply type it into the browser as http and the server would never know), negating the whole point of HTTPS.
I tried checking if %{HTTP_REFERER} referenced itself, but it did not using mod_rewrite.
The only workaround I can come up with is through client-side detection with javascript. This has its own pitfalls (NoScript, etc). But I cannot come up with another solution to the problem. The following code will approximate a 301 redirect.
if(document.URL.match(/^https/i) == null) {
var NetworkSolutionsSucks = document.createElement('meta');
with (NetworkSolutionsSucks) {
httpEquiv = 'refresh';
content = '0;url=' + document.URL.replace(/^http/i,'https');
}
document.head.appendChild(NetworkSolutionsSucks);
var msg = document.createElement('div');
with (msg) {
innerHTML = 'This page requires a secure connection, you are being redirected.<br><br>';
innerHTML += 'If the page does not load, please click Here';
}
var newBody = document.createElement('body');
newBody.appendChild(msg);
document.replaceChild(newBody, document.body);
}
Include the above script in the header of any document you want to force HTTPS (forcing HTTP is left as an exercise for the reader - it's a simpler script, not requiring the manual redirect on some failure). You should use a noscript tag with this (obviously); you can use the following:
<noscript id="networkSolutionsHTTPSRedirect">This site requires javascript in order to operate properly. Please enable javascript and refresh this page.</noscript>
<style type="text/css">#networkSolutionsHTTPSRedirect{position: fixed; height: 100%; width: 100%; top: 0; left: 0; z-index: 500;}</style>
<script type="text/javascript">
<!--
document.getElementById("networkSolutionsHTTPSRedirect").style.visibility = "hidden";
document.getElementById("networkSolutionsHTTPSRedirect").style.display = "none";
-->
</script>
EDIT: I figured out a way to do this server side:
You can try to force the entire site to HTTPS if you do the following on every page:
<?php
if((!isset($_ENV['HTTP_REFERER']) || preg_match('/^http[s]{0,1}:\/\/' . $_ENV['SERVER_NAME'] . '/i',$_ENV['HTTP_REFERER']) == 0) && !isset($_ENV[HTTP_X_HTTPS_REDIRECT])) {
header('X-HTTPS-REDIRECT: true\n');
header('Location:' . preg_replace('/^http/','https', $_ENV['SCRIPT_URI']));
}
?>
This should introduce a redirect to all requests that don't have HTTP_REFERER set to your site and do not carry the custom X-HTTPS-REDIRECT header that you inject. This doesn't really detect HTTPS, but performs a reasonable facsimile (at least its server side).
You could, of course, modify the regex so that only certain sites need to be HTTPS by matching the REFERER to the portion of your domain that you want secured and then negate the test to force HTTP.

I have Network Solutions as my provider as well. This last attempt at scripting with PHP also did not work, resulting in an infinite loop.
Network Solutions offers the following code as the best redirect available from http:// to https:// in Javascript, saying that there is no way to do it server side.
<script language="javascript">
if (document.location.protocol != "https:")
{
document.location.href = "https://subdomain.yourdomain.com" + document.location.pathname;
};
</script>
Their information on the subject can be found here. http://www.networksolutions.com/support/ssl-redirects/

Use the following to force only certain pages to https. In your section to force http, just include the sections/pages that force https in a negated format.
Something like this, perhaps: (.htaccess)
Options +FollowSymLinks
RewriteEngine On
RewriteBase /
# Force https for mode= login, account or register, and the /admin directory:
RewriteCond %{HTTPS} !=on
RewriteCond %{QUERY_STRING} mode=(login|account|register) [OR]
RewriteCond %{REQUEST_URI} admin/
RewriteRule (.+) https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
# force http for all NON login, account, register (query string)
# and anything else outside the /admin directory
RewriteCond %{HTTPS} on
RewriteCond %{QUERY_STRING} !mode=(login|account|register)
RewriteCond %{REQUEST_URI} !admin/
RewriteRule (.+) http://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]

The PHP variable:
$_ENV['SCRIPT_URI']
will return the full request string, including protocol.
<?php
if(preg_match('/^https/i',$_ENV['SCRIPT_URI']) == 0) {
header('Location: ' . preg_replace('/^http/i','https', $_ENV['SCRIPT_URI']));
}
?>

This is the ONLY Clean way to Redirect with Networksolutions. Took me hours of testing. Works best for SEO. Network Solutions is a challenging Hosting platform.
This will work .htaccess all you replace is changeexample.com with your domain. Easy.
## Base Redirects ##
# Turn on Rewrite Engine
RewriteEngine On
# Remove trailing slash from non-filepath urls
RewriteCond %{REQUEST_URI} /(.+)/$
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ https://changeexample.com/%1 [R=301,L]
# Include trailing slash on directory
RewriteCond %{REQUEST_URI} !(.+)/$
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+)$ https://changeexample.com/$1/ [R=301,L]
# Force HTTPS and remove WWW
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [OR,NC]
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://changeexample.com/$1 [R=301,L]
Best of Luck! This is current as of 05/14/2021

Related

Force HTTPS redirection on whole website except for 1 single page

My SSL is managed by cloudFlare but I prefer using htaccess method to control redirection of site to use HTTPS. I have a domain www.mysite.com and a sub domain demo.mysite.com. I want HTTPS on full website of www.mysite.com and on full website of demo.mysite.com as well except for just 1 page on my subdomain to prevent mixed content. That page can contain both HTTP and HTTPS links loaded in iFrame. Currently that page loads in HTTPS along with whole website but I want it to load in HTTP only and not HTTPS. The page is demo.mysite.com/surf.php which can be accessed by clicking an Ad at demo.mysite.com/ads.php.
I tried this in my htaccess file but the page surf.php still redirects to HTTPS.
# FORCE HTTPS
RewriteCond %{SERVER_PORT} 80
RewriteCond %{REQUEST_URI} \/(surf.php)
RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
# DISABLE HTTPS
RewriteCond %{HTTPS} on
RewriteCond %{SCRIPT_FILENAME} !\/(surf.php) [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ http://%{HTTP_HOST}$1 [R=301,L]
I have disabled "Always use HTTPS" in my cloudFlare settings and my SSL is Flexible. Also, no page rules are set. I prefer htaccess method. Please help me and tell me what to do?
I have the following working on a domain in Cloudflare that has a flexible Cloudflare cert.
Instead of using .htaccess I have 2 Cloudflare page rules.
The first rule:
*.domain.com/page-to-ignore.htm
SSL: Off
Second rule:
http://*.domain.com/*
Always Use HTTPS
The order matters, and when testing on your own site, make sure you have cleared your browser cache.
Hope this helps!
If you are still facing trouble then you can also use a PHP code instead. Paste this code on your header file of the website or paste on each page where you want the website to be redirected to HTTPS or HTTP. Make sure to disable "Always use HTTPS" in cloudFlare and you can choose any SSL you want i.e, Flexible, Full or Full (strict).
PHP code for redirecting to HTTPS:
if($_SERVER['HTTP_HOST'] != 'localhost'){
if(!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] !== 'on'){
if(!headers_sent()){
header("Status: 301 Moved Permanently");
header(sprintf('Location: https://%s%s',$_SERVER['HTTP_HOST'],$_SERVER['REQUEST_URI']));
exit();
}
}
}
PHP code for redirecting to HTTP:
if($_SERVER['HTTP_HOST'] != 'localhost'){
if(isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == 'on'){
if(!headers_sent()){
header("Status: 301 Moved Permanently");
header(sprintf('Location: http://%s%s',$_SERVER['HTTP_HOST'],$_SERVER['REQUEST_URI']));
exit();
}
}
}
This worked for me pretty well. Paste the code at the top of each page. If you are using session_start(); then place this code immediately after that. That's a good practice.

Htaccess and redirecting from https page to non https page

I have a website where all URLs are rewritten to avoid seeing extensions and the original file name. So, in my htaccess, I have the following:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^example-1$ filename_1.php
RewriteRule ^example-2$ filename_2.php
Now, I also have a few pages that I wanted to be only https and only http. So, let's say I want filename_1 to alwaysbe https and filename_2 to always be http. So, I have the following codes.
RewriteCond %{HTTPS} off
RewriteRule ^(filename_1)\.php$ https://%{HTTP_HOST}%{REQUEST_URI} [L,NC,R]
And
RewriteCond %{HTTPS} on
RewriteRule ^(filename_2))\.php$ http://%{HTTP_HOST}%{REQUEST_URI} [L,NC,R]
This is just and example but I actually have many files affected by those two rules.
Now, I thought it was working great until I noticed that when I am on an https page and I access a non https page, the url changes to show the actual file name. So, if I am on https://www.mywebsite.com/example-1 and I try to access example-2, the url changes to http://www.mywebsite.com/filename_2.php instead of http://www.mywebsite.com/example-2. And the same for going from http to https. (I am keeping it simple in those examples but the problem only arise with pages with variables in the url. Simple ones like www.mywebpage.com/homepage work just fine.)
So, I added this line of code:
RewriteCond %{HTTPS} on
RewriteCond %{REQUEST_URI} !^/(example-2)/ [NC]
RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1 [L,R=301,NE]
So, it worked to go from https to http but then things just got crazy! I get redirect loops at certain https and non https page and I have no clue why! The thing is that I started by adding one page at a time to this new rule. And pages that I haven't even added yet give me some redirect loop. Then I try adding those pages but instead of https on, I used https off and it got even crazier.
So my question is what is a good way to have all the following perform harmoniously:
1. Rewrite all urls to custom ones
2. Having http and https page while keeping the custom urls and avoiding all redirect loops.
Thanks!

Why isn't RewriteCond %{HTTPS} returning the correct value?

I am working on a Drupal site for which the client has requested that we remove the 'www.' from the URL. This is super easy and I've done it before; I simply comment out the suggested lines in the Drupal-generated .htaccess file like so:
# To redirect all users to access the site WITHOUT the 'www.' prefix,
# (http://www.example.com/... will be redirected to http://example.com/...)
# uncomment the following:
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ http%{ENV:protossl}://%1%{REQUEST_URI} [L,R=301]
Those of you familiar with Drupal's .htaccess will know that the environment variable protossl is set towards the top of the file like so:
# Set "protossl" to "s" if we were accessed via https://. This is used later
# if you enable "www." stripping or enforcement, in order to ensure that
# you don't bounce between http and https.
RewriteRule ^ - [E=protossl]
RewriteCond %{HTTPS} on
RewriteRule ^ - [E=protossl:s]
This is working perfectly on my local environment, but when I deployed the change to the production site it breaks. www.mysite.com redirects to mysite.com as expected, but https://www.mysite.com also redirects to mysite.com instead of https://mysite.com. It seems that the %{HTTPS} variable is returning 'off' even when it should be 'on'.
I can go directly to https://mysite.com and it works perfectly. The site's Apache access logs show 'https://' where I expect it to be, as do all of my HTTP requests. The site is running on a RackSpace server using a load balancer (only one node in the balancer). The SSL certificate is on the RackSpace load balancer. I have tried the following steps and none have had any results:
Replace RewriteCond with RewriteCond %{ENV:HTTPS} on [NC]
Replace RewriteCond with RewriteCond %{SERVER_PORT} ^443$
Multiple variations and combinations of the above RewriteCond's
Added $conf['https'] = TRUE; to settings.php
This is driving my coworkers and I crazy. Can anyone help?
anubhava has saved the day! The solution was to use the %{HTTP:X-Forwarded-Proto} variable just as he suggested. I updated the protocol detection bit of my .htaccess to look like this:
# Set "protossl" to "s" if we were accessed via https://. This is used later
# if you enable "www." stripping or enforcement, in order to ensure that
# you don't bounce between http and https.
RewriteRule ^ - [E=protossl]
# The default proto detection provided by Drupal does not work on our
# production server because it sits behind a load-balancing server.
# This additional RewriteCond makes sure we can detect the forwarded proto
RewriteCond %{HTTP:X-Forwarded-Proto} https [OR]
RewriteCond %{HTTPS} on
RewriteRule ^ - [E=protossl:s]
I'm gonna call this a crunchwrap supreme, 'cause it is good to go!

.htaccess https redirect for a single page (using relative urls)

I need to be able to redirect a single page from standard http to https. For example, I want to go from http://domain.com/quote.php to https://domain.com/quote.php.
So far I'm using this code in my .htaccess file, and it's working for the initial redirect.
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^quote.php https://domain.com/quote.php [R=301,L]
My problem, is that once I have visited the quote.php page and get redirected to the https version, all the other site pages I navigate to continue using the https protocol. This is a potential duplicate content issue, as I now have the same content accessible via http and https.
So what I want to do, is be able to do the above redirect, and then somehow do the same thing in reverse for all pages except quote.php. So if you attempted to access them via https, it would redirect to the default http version.
I use relative URLs throughout the site, so I can't simply hard-code in the https/http prefix. I need to be able to do this via .htacess, if possible.
Any help is greatly appreciated.
RewriteCond %{HTTPS} off
RewriteRule ^quote.php$ https://domain.com/quote.php [R=301,L,QSA]
RewriteCond %{HTTPS} on
RewriteCond %{REQUEST_URI} !^/quote.php
RewriteRule ^(.*)$ http://domain.com/$1 [R=301,L,QSA]
answer to comment:
for adding new page to conndtions just put them parenthesis.like:
RewriteCond %{HTTPS} off
RewriteRule ^(quote|contact).php$ https://domain.com/$1.php [R=301,L,QSA]
question 2: QSA flag add current query string to new URL. it happens by default except in case you change query string. You can delete them now safely but if you have added query string, and wanted to have old one too, put that back.
Edit 2:
code above has a little security issue :(, actually it's more than a little :-D.
when you are using https to transfer html codes and page is using relative paths, so that's fine. but when you put these codes in .htaccess they turn into http and that's the problem:-). put the code below to sove the problem:):
RewriteCond %{HTTPS} off
RewriteRule ^(quote|contact).php$ https://domain.com/$1.php [R=301,L,QSA]
RewriteCond %{HTTPS} on
RewriteCond %{REQUEST_URI} !^/(quote|contact).php
RewriteCond %{REQUEST_URI} !^/(.*)\.(css|png|js|jpe?g|gif|bmp)$
RewriteRule ^(.*)$ http://domain.com/$1 [R=301,L,QSA]
Now, all images,scripts,.. that you are using on secure pages, are transferring securely.

.htaccess subdomains redirect is not working

Ok, now I am lost.
I am trying to do a simple .htaccess redirect of subdomains to a specific folder on the server, meaning all
subdomain.mywebsite.com
will go to
www.mywebsite.com/s_subdomain
But for some reasons this doesn't work.
I have tried a lot of settings in .htaccess but for no good. Now in my .htaccess I have:
RewriteEngine on
Options +FollowSymLinks
Options +SymlinksIfOwnerMatch
RewriteCond %{HTTP_HOST} !^(www|ftp|mail)\.mywebsite\.com
RewriteCond %{HTTP_HOST} ^([^.]+)\.mywebsite\.com
RewriteRule (.*) /s_%1/$1 [L]
Are there any other settings, or is somethig I have missed?
PS. - I don't have access to http.conf. I have to do it using only .htaccess
Thanks!
This is just a "plain" rewrite (the browser won't see it). To redirect, add the R flag to your RewriteRule.
RewriteRule (.*) /s_%1/$1 [L,R]
The rest seems right, although I haven't tested it. For debugging you could consider RewriteLog, see http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html#rewritelog
So, neither solution does work? Try something simple then.
RewriteEngine on
RewriteCond ${SERVER_NAME} ^(subdomain)\.yoursite\.com$ [nc]
RewriteRule ^(.*)$ http://www.yoursite.com/s_%1/$1 [L,R]
To test if your subdomain is handled correctly, create random.html file, place it where it should be read from, and try opening it via http://subdomain.yoursite.com/random.html. Then you can try some stuff like:
RewriteRule ^random.html - [F]
...and if that blocks access to file, try prepending
RewriteCond ${SERVER_NAME} ^subdomain\.yoursite\.com$ [nc]
to previous rule, to block access to that file, to make sure that rewrite engine is actually hitting your rules. That would target only desired subdomain (www.yoursite.com/random.html should work, but access via subdomain shouldn't).
Then if those rules work, it's just a matter of adding more stuff and see when it stops working.
RewriteRules are a bitch.
The following should work:
.htaccess:
RewriteCond ${SERVER_NAME} !^(www|ftp|mail)\.example\.com$
RewriteCond ${SERVER_NAME} !^([^.]+)\.example\.com$
RewriteRule .* redirect.php?to=%1
redirect.php
<?php
$desired_server_name = 'http://example.com';
$subdir = 's_' . $_GET['to'];
$url = $desired_server_name . '/' . $to . $_SERVER['REQUEST_URI'];
// Permanent redirects
header('HTTP/1.1 301 Moved Permanently');
// Or simple redirects:
header('HTTP/1.1 302 Found');
header('Location: '.$url);
?>
Works on my server (debian 4/apache 2).
Bonus: do not EVER use HTTP_HOST! See the following request:
HTTP/1.1 GET /foo/bar.php
Host: www.host.tld"><script>alert(/Hello/)</script
Connection: close
If you use $_SERVER['HTTP_HOST'] in your .php scripts to construct links or .htaccess rules for that matter and "www.host.tld" is the virtual-host or the only host configured for Apache, the XSS in the HTTP request header will be passed down unescaped.
We have a similar thing working on our Virtual Machines, where we redirect anything.usertld to a folder for that domain, that was in httpd.conf, tried in in the .htaccess and like yours it didn't work.
Tweaking it, this works for me (my VM occupies a tld called benb, but changing it to your domain should be fine):
RewriteCond %{HTTP_HOST} !^www\.benb
RewriteCond %{HTTP_HOST} ^(.*)\.benb
RewriteCond %{REQUEST_URI} !^/{0,1}s_
RewriteRule ^(.*)$ s_%1/$1 [L]
Also this captures all the text before the domain.. you should be able to change:
RewriteCond %{HTTP_HOST} ^(.*)\.benb
to
RewriteCond %{HTTP_HOST} ^([^.]+)\.benb
to handle just 1 level of subdomain. Also your other part about (www|ftp|mail) would work fine too.

Resources