Is there a way to check if the current page was opened with SSL? For example, I want my login page (login.php) to check if it was accessed using SSL (https://mywebserver.com
Well, Here is another chunk of code. The code will return full url with https/http.
<?php
/**
* Check whether URL is HTTPS/HTTP
* @return boolean [description]
*/
function isSecure()
{
if (
( ! empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
|| ( ! empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
|| ( ! empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on')
|| (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443)
|| (isset($_SERVER['HTTP_X_FORWARDED_PORT']) && $_SERVER['HTTP_X_FORWARDED_PORT'] == 443)
|| (isset($_SERVER['REQUEST_SCHEME']) && $_SERVER['REQUEST_SCHEME'] == 'https')
) {
return true;
} else {
return false;
}
}
/**
* Example Use
*/
define('APP_URL', (isSecure() ? 'https' : 'http') . "://{$_SERVER['SERVER_NAME']}".str_replace(basename($_SERVER['SCRIPT_NAME']),"",$_SERVER['SCRIPT_NAME']));
echo APP_URL;
/**
* +++++++++++++++++++++++++
* OR - One line Code
* +++++++++++++++++++++++++
*/
define('APP_URL', ((( ! empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || ( ! empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') || ( ! empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on') || (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) || (isset($_SERVER['HTTP_X_FORWARDED_PORT']) && $_SERVER['HTTP_X_FORWARDED_PORT'] == 443) || (isset($_SERVER['REQUEST_SCHEME']) && $_SERVER['REQUEST_SCHEME'] == 'https') ) ? 'https' : 'http') . "://{$_SERVER['SERVER_NAME']}".str_replace(basename($_SERVER['SCRIPT_NAME']),"",$_SERVER['SCRIPT_NAME']));
echo APP_URL;
?>
To use PHP to check if the page was accessed without SSL you can check the port number.
// Most encrypted web sites use port 443
if ($_SERVER['SERVER_PORT']==443) {
// Tell browser to always use HTTPS
header('strict-transport-security: max-age=126230400');
}
elseif (isset($_SERVER['SERVER_PORT'])) {
// Redirect current page to https with 301 Moved Permanently response
header('location: https://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'], true, 301);
exit;
}
This assumes your server is configured with the SERVER_PORT environment variable and that the encrypted version of your web site is hosted on port 443. It also assumes your server is not behind a load balancer. If your server is behind a load balancer, you might need a more advanced solution such as this one that does not rely on custom HTTP headers which can vary from one load balancer to the next:
// Set secure cookie to detect HTTPS as cookie will not exist otherwise.
header('set-cookie: __Secure-https=1; expires='.substr(gmdate('r', ($_SERVER['REQUEST_TIME']?: time())+126230400), 0, -5).'GMT; path=/; secure', false);
// Tell browser to always use HTTPS
header('strict-transport-security: max-age=126230400');
if (!isset($_COOKIE['__Secure-https']) && !isset($_GET['https'])) {
// Redirect to secure version of site and add https=1 GET variable in case cookies are blocked
header('location: https://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'].(strpos($_SERVER['REQUEST_URI'], '?')===false? '?': '&').'https=1', true, 307);
exit;
}
If the above solution is problematic because it adds ?https=1 to your URL then you can always use JavaScript. Add this to the top of your page right after <head>:
<script>
// This will redirect all requests from http to https
if (location.protocol=='http:') {
location.replace('https://'+location.host+location.pathname+location.search)
document.write('<noscript>');// hack to stop page from displaying
}
</script>
Then add the following to your PHP script if you want browsers to remember to always use HTTPS when accessing your site:
header('strict-transport-security: max-age=126230400');
or if you want browsers to have your preferences preloaded use:
header('strict-transport-security: max-age=126230400; preload');// HTTPS will always be used!
If you use the preload feature you will need to submit your web site to be included in Chrome's HSTS preload list so that browsers come preloaded with your web site preferences. If you use preload, it's also advisable to host your site on the naked domain without the www. This is because it's usually easier for most people to type in your domain without the www, and with preload your web site loads without the need of a tedious redirect since https is already the default.
Be careful. On my IIS server, $_SERVER['HTTPS'] is not empty but has the value 'off'.
So i had to do
if (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != 'on') {
// no SSL request
}
Another method is to check for the existence of HTTPS cookies. First your server needs to send the browser a cookie with the secure
flag:
Set-Cookie:some_key=some_value;secure
After your server has sent the browser the cookie, whenever the browser requests a page from your server, it will send along the secure cookie some_key=some_value
only if it is requesting a HTTPS page. This means that if you see the existence of the cookie some_key=some_value
you know that the browser is requesting a HTTPS page. Voila!
Browser support is very good, as this is fundamental to security. Browsers without support for HTTPS cookies are Firesheepable when users request pages from non-HSTSed domains.
For more info, see:
https://httpsnow.org/help/securecookies
https://www.owasp.org/index.php/SecureFlag#Overview
https://stackoverflow.com/a/13730187/632951
https://security.stackexchange.com/q/100/2379
You'll find this may not work if you are working over forwarded protocols. For example, Amazon's ELB can handle SSL negotiation and interact with your app servers over port 80.
This block handles that:
public function isSSL()
{
if( !empty( $_SERVER['https'] ) )
return true;
if( !empty( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' )
return true;
return false;
}
Just to add that in case of nginx, the way to check for https is:
if (isset($_SERVER['SERVER_PORT']) &&
($_SERVER['SERVER_PORT'] === '443')) {
return 'https';
}