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,
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]
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/
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']));
}
?>
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 <a href="' + document.URL.replace(/^http/i,'https') + '">Here</a>';
}
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>
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.