I need a PHP if/else statement that if the sign-in.php or register.php page is access over HTTP I would like to redirect to HTTPS else if any other page is accessed over HTTPS redirect to HTTP plus have any query string appended for example if a user tries to access a restricted page (http://domain.com/my-account.php) the site redirects the user to http://domain.com/sign-in.php?redirect=my-account however, I would like the page to redirect to https://domain.com/sign-in.php?redirect=my-account.
I know I could simply change the header redirects to include https instead of http but users may type http://domain.com/sign-in.php?redirect=my-account so just need to ensure if this happens sign in (or others) happen over https.
Any help is appreciated
Here You go.
//force the page to use ssl
if ($_SERVER["SERVER_PORT"] != 443) {
$redir = "Location: https://" . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
header($redir);
exit();
}
$_SERVER, It is an array containing information such as headers, paths, and script locations.
You can check against $_SERVER, specifically 'SERVER_PROTOCOL'
http://php.net/manual/en/reserved.variables.server.php
There should be a part of your code that is always run on every page. In an MVC it would be in your base controller. Other designs may include an init.php file on every page.
In this file have a whitelist of pages that require HTTPS.
$requires_https = array(
'sign-in.php' => TRUE,
'register.php' => TRUE
);
Then you need to determine which page was requested.
$url_info = pathinfo($_SERVER['REQUEST_URI']);
$page = $url_info['filename'];
Next check if you are on HTTP or HTTPS
$is_secure = ! empty($_SERVER['HTTPS']);
Finally you can do the checking:
if (isset($requires_https[$page]) AND ! $is_secure)
header('Location: https://www.yoursite.com/' . $page);
elseif ( ! isset($requires_https[$page]) AND $is_secure)
header('Location: http://www.yoursite.com/' . $page);
This could definitely be improved upon in the last part by using a custom redirect function and a site_url function that takes in the option of being secure or not and builds the proper URL.
It is worth mentioning that it generally doesn't matter if someone is left surfing in HTTPS. In fact most of Google's services are in HTTPS and with better internet connections surfing will eventually all be done in HTTPS. It is only important to make sure the pages that should be secure are secure, not make sure that pages that don't need to be secure aren't.
if ($_SERVER['SERVER_PORT'] != 443) {
header("HTTP/1.1 301 Moved Permanently");
header("Location: https://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
exit();
}
Using part of an init class / script -
You can run code to check if this page should require SSL prior, but this is the actual code to force redirect to SSL (and REQUEST_URI provides any dirs, etc.. to get the correct path).
Using on a single page (i.e. sign-in and register) -
This will redirect the user to this page in SSL (put this code near the top).
The 301 Moved Permanently will also prevent any negative SEO.
(A more) complete method: (includes the query string)
To determine if on https:
$secure = (!empty(filter_input(INPUT_SERVER, 'HTTPS')) &&
filter_input(INPUT_SERVER, 'HTTPS') !== 'off') ||
filter_input(INPUT_SERVER, 'SERVER_PORT') == 443;
as per https://stackoverflow.com/a/2886224
Then to redirect and include the query string:
if($secure){
header("Location: https://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
}
Using REQUEST_URI instead of PHP_SELF will include the query parameters (things after the ? in the URL).
And as always filter your user input (including these) with filter_input() or the like.
Related
I am trying to redirect only the index page of my website to HTTPS version using the following code but it gives domain.com redirected you too many times i.e ERR_TOO_MANY_REDIRECTS error.
There are no redirect codes in htaccess except the 4XX & 5XX error redirections.
if($_SERVER['HTTPS'] !== "on")
{
$redirect= "https://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
header("Location:$redirect");
}
How to redirect only one page to HTTPS without affecting other URLs in PHP?
Your problem is in this line
if($_SERVER['HTTPS'] !== "on")
Per the manual
'HTTPS' : Set to a non-empty value if the script was queried through the HTTPS protocol.
So just use
if(!$_SERVER['HTTPS'])
Here is my code for doing redirect for non www pages. You can adapt it easily for https.
// redirect to www if necessary
$kc_ur_pos = stripos($_SERVER['HTTP_HOST'],'www.');
if ($kc_ur_pos === false)
{ $kc_ur='https://www.';
$kc_ur .= $_SERVER['HTTP_HOST'];
$HTTPURI = $kc_ur . $_SERVER['REQUEST_URI'];
header("HTTP/1.1 301 Moved Permanently"); // Optional.
header("Location: $HTTPURI");
exit;}
I used info from this answer (https://stackoverflow.com/a/85867/3271766 - along with the contribution from Dave1010) to allow me to force a page to load securely (https://). This works beautifully!
Now, I want to do the opposite. When clicking a relative link (to a normal, non-secure page) from a secure page, I want to force that page to load non-securely (http://). I don't want to use absolute links to accomplish this. They need to stay relative. Instead, I'd rather use a piece of PHP code similar to what I used to force pages to load securely.
How can this be done? Thanks, in advance, for your help.
The code I used (in each page's head tags) to force pages to load securely is:
<?php
// WORKING: FORCE SECURE - Force page to load securely (http:// > https://)
if(empty($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] !== "on")
{
header("Location: https://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]);
exit();
}
?>
I tried the following, but it stops the page from loading altogether:
<?php
// NOT WORKING: FORCE NON-SECURE - Force page to break out of secure protocol (https:// > http://)
if(empty($_SERVER["HTTP"]) || $_SERVER["HTTP"] !== "on")
{
header("Location: http://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]);
exit();
}
?>
Is there a way to modify this to make it work?
(By the way, in case anyone is wondering, I am doing this because a third-party sharing tool my client wants to use does not have a valid security certificate. Thus, portions of the sharing tool either do not load, or do not function. I have contacted the vendor repeatedly, but they have not responded. I have removed the tool from the secure pages only. However, my client wants to use this tool on all other pages, on which it works perfectly, so long as it is not accessed securely.) :-)
Regards,
Jeremy
Change
if(empty($_SERVER["HTTP"]) || $_SERVER["HTTP"] !== "on")
to
if(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on'){
$url = 'http://'. $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
header("Location: $url");
}
i have a login form:
<form method =POST action="/login.php">
...
</form>
i would like the login.php page to redirect to using https.
i don't want to send the user to https://.../login.php because they might change the link. but i want to do a redirect on the server side before i parse the login form data and log the user in.
i found and example:
if($_SERVER["HTTPS"] != "on") {
header("HTTP/1.1 301 Moved Permanently");
header("Location: "https://" . $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"]);
exit();
}
but i don't have $_SERVER["HTTPS"] if i var_dump($_SERVER);
i do have $_SERVER['SERVER_PORT'] witch is 80.
any ideas?
Thanks
If you allow them to post to /login.php over plain HTTP and then redirect to HTTPS, you defeat the purpose of using HTTPS because the login information has already been sent in plain text over the internet.
What you could do to prevent the user from changing the URL, is make it so the login page rejects the login if it is not over HTTPS.
What I use to check for the use of HTTPS is the following:
if (!isset($_SERVER['HTTPS']) || !$_SERVER['HTTPS']) {
// request is not using SSL, redirect to https, or fail
}
If you are running your secure server on the default port of 443, then you can also check to see if that is the port, but PHP sets the $_SERVER['HTTPS'] value to non-empty if SSL is used so I would check for the presence of that for best practice.
EDIT:
If the user is so included to manually change the https to http and want to send their information over plain text, there isn't anything you can do to stop them, but if you disallow login over HTTP, so even the correct information will not log them in, you can force them to use https by making it the only thing that works.
Whatever page you use to display your login form should already be using https:// before the form is filled out, and then it should be submitted to another https:// address. Otherwise, you'll leave the form open to attack.
You could look into mod_rewrite to automatically redirect any request using http:// to https://, at least for your login page.
if($requireSSL && $_SERVER['SERVER_PORT'] != 443) {
header("HTTP/1.1 301 Moved Permanently");
header("Location: https://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
exit();
}
Assuming that your page with the login form is generated by index.php, you need to put the example code for HTTP to HTTPS redirection in index.php. This will ensure that when the user fills up the form and submits it, it is submitted to /login.php via HTTPS and not HTTP.
Putting this check inside login.php is futile because by the time login.php gets the request and tries to redirect to the corresponding HTTPS URL, well, the credentials have already been submitted to it as plaintext which is what you should want to avoid.
The observation that you see $_SERVER['SERVER_PORT'] to be 80 and $_SERVER["HTTPS"] to be not set when you put the check inside login.php is a further proof of the fact that login credentials are being submitted to it via HTTP and thus the login credentials are reaching your server from the client unencrypted. This has to be avoided by following what I said in the first paragraph of this response.
BTW, I wouldn't use PHP to do this sort of redirection. Such redirections are very conveniently handled by mod_rewrite in Apache HTTPD.
An example, assuming that your login page is available at the URL, http://example.com/foo/:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^foo/$ https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
I just had an ssl installed for a site I am working on and I obviously need to get a few of the pages (checkout etc) redirected to https.
I am currently using this code:
if (!isset($_SERVER['HTTPS']) || !$_SERVER['HTTPS']) {
$url = 'https://www.mysite.php';
header("location: ". $url);
exit();
}
Firefox is telling me that "the page is trying to redirect in a way that will never complete."
A var_dump of $_SERVER shows no ['HTTPS'] or similar when I am on the secure page. This is on a Network Solutions small unix package. Is it possible I need to be checking for a different server variable or perhaps I need to change some server settings?
Clearly the script is never finding HTTPS so it is trying to redirect without end.
It becomes clearer if you use OR:
if (!isset($_SERVER['HTTPS']) OR !$_SERVER['HTTPS']) {
Chances are one of the conditions always evaluates to true, even when you already are in HTTPs mode.
You want AND:
if (!isset($_SERVER['HTTPS']) AND !$_SERVER['HTTPS']) {
I use this form of SSL Checking too. For me my code works. Here is what i do.
if(empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") {
header("Location: https://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
}
This works great and also redirects you to the previous url.
hope this helps.
I have a site which has a public and a private area. The private area
should be served via HTTPS. I want to redirect once to an explicit HTTPS url, and then, using relative URLS, have all the links be secure. When the user logs out, I will explicitly link to an absolute non-secure HTTP URL.
My login form is shown a non-secure site via regular HTTP. My login form posts to https://www.mysite.com/login/validate , which loads using a secure connection.
My logs show that Apache is loading the URL via HTTPS and codeigniter is doing its validation correctly.
At the end of my controller function I redirect to /myaccount using CodeIgniter's URL helper's redirect method with a relative URL.
redirect('/myaccount');
This causes codeigniter to redirect to a non-HTTPS URL.
My config base_url is non-HTTPS:
$config['base_url'] = "http://www.mysite.com"
This is because some parts of the site are secure while others are not.
Is there a way to tell CodeIgniter to preserve HTTPS when doing relative redirects? Why is it assuming I want to go to a non-HTTPS site if the current controller was loaded via HTTPS and I am doing a relative redirect?
The desired behavior for me is that if I am doing relative redirect, it should preserve the protocol through which the current request was loaded. Instead, it is switching to what the config base_url has defined, even for relative redirects.
Use this:
$config['base_url'] = "http".((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == "on") ? "s" : "")."://".$_SERVER['HTTP_HOST'].str_replace(basename($_SERVER['SCRIPT_NAME']),"",$_SERVER['SCRIPT_NAME']);
Instead of this:
$config['base_url'] = "http://www.example.com"
This'll always redirect to where you want it. You don't even have to enter your domain name, just use it as is!
In addition to the above, I also autoload this helper:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
function is_https_on()
{
return isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on';
}
function use_ssl($turn_on = TRUE)
{
$url = $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
if ( $turn_on )
{
if ( ! is_https_on() && $_SERVER['HTTP_HOST'] != 'localhost')
{
redirect('https://' . $url, 'location', 301 );
exit;
}
}
else
{
if ( is_https_on() )
{
redirect('http://' . $url, 'location', 301 );
exit;
}
}
}
/* End of file https_helper.php */
/* Location: ./application/helpers/https_helper.php */
With this in place, I can set my individual pages to always use HTTPS/HTTP (either in a single method in my controller, or - if I want it to affect the whole controller - in the constructor).
I simply use:
use_ssl();
at the beginning of the script, to ascertain that it is loaded via HTTPS.
Alternatively, if I only want to serve it through HTTP, I'll use:
use_ssl(FALSE);
There is no 'out of the box' way to handle this HTTPS / HTTP handoff in CI. What you CAN do is create a small helper (that you auto include) which will add a function like secure_url(), and quite simply returns what a base_url would, but https format.
You would have to emulate the same redirect function maybe as secure_redirect().
you can use a protocol-relative url which will keep persistence in the linking in CI.
in your config.php instead of:
$config['base_url'] = 'http://example.com/';
put;
$config['base_url'] = '//example.com/';
information about protocol-relative links here.
i have tested this on ie11,chrom(e|ium),firefox,midori using CI form library and basic links. all the browsers honor the specification and i have seen this used in the wild without issue.
additionally CI version 3 has a is_https function built in
you should be able to simple use is_https in your controller (eg in the construct) and redirect if not https, then useing the above method maintain http or https without constant redirections.
eg, to keep the entire controller as https, insert into your controller:
public function __construct()
{
parent::__construct();
$this->load->helper('url');
if(! is_https()){
redirect('https:'.base_url('/page'));
}
//!! $conig['base_url'] must be protocol-relative
}