Session lost when switching from HTTP to HTTPS in PHP

PhpSessionSslHttps

Php Problem Overview


When sending the user to a checkout page, they are switched from http://sitename.com to https://sitename.com.

As a result, $_SESSION variables are lost.

The site has a valid SSL certificate which may or may not be of some use.

Php Solutions


Solution 1 - Php

When you switch between the HTTP and HTTPS services on the same server, your HTTP session ID is not being passed to the HTTPS session. You can set it by passing the session ID from the HTTP page to the HTTPS page in one of three possible ways:

From PHP: session_start:

> session_start() creates a session or resumes the current one based > on the current session id that's being passed via a request, such as > GET, POST, or a cookie

When you are using sessions, you will normally start your script with session_start(). If the browser has a session ID cookie set, session_start() will use that session ID. If the browser does not have a session ID cookie set, session_start() will create a new one.

If the session ID is not set(in your example, the browser is creating a new session ID cookie for the HTTPS session), you can set it using the session_id() function. session_id() also conveniently returns the session ID as a string. So

...

$currentSessionID = session_id();

...

sets the $currentSessionID variable equal to the current session ID, and

...

session_id($aSessionID);

...

sets the sessionID cookie in the browser to $aSessionID. from PHP: session_id

Here's an example with two scripts. One is accessed via HTTP and the other is accessed via HTTPS. They must be on the same server to maintain session data.

Script 1(HTTP):

<?php

// This script will create a session and display a link to your secure server address
// to transfer your session ID. In this example, the secure page to receive the session
// ID is located at http://www.yoursite.com/safePages/securePage.php

// Start a session using the current session ID stored in a cookie, or create
// a new session if none is set.
session_start();

$currentSessionID = session_id();

// Set a variable that will be retrieved with the HTTPS script.
$_SESSION['testvariable'] = 'It worked';

// $secureServerDomain is the domain of your secure server
$secureServerDomain = 'www.yoursite.com';

// $securePagePath is the path to the page that will receive and set the session ID.
$securePagePath = '/safePages/securePage.php'

echo '<a href="https://' . $secureServerDomain . $securePagePath . '?session="' . $currentSessionID . '">Click here to transfer your session to the secure server</a>';

?>

Script 2(HTTPS):

<?php

// Retrieve the session ID as passed via the GET method.
$currentSessionID = $_GET['session'];

// Set a cookie for the session ID.
session_id($currentSessionID);

// Start a session.
session_start();

// Test retrieval of variable set when using HTTP.
if (!empty($_SESSION['testvariable'])) {
      echo $_SESSION['testvariable'];
} else {
      echo 'It did not work.';
}

?>

For this to work the HTTP and HTTPS servers must use the same session data storage substrate (i.e. for the default files handler, run on the same physical machine with the same php.ini). There are some security flaws here, so I would not use this code to transfer sensitive information. It is just meant as a workable example.

When I ran into this problem before, I came up with the above as a quick fix, but I just remembered the original cause of the problem. I was going from http://www.example.com/page.php to https://example.com/page.php (notice the lack of "www"). Make sure that http://www.example.com/page.php will link to https://www.example.com/page.php and http://example.com will link to https://example.com/page.php.

PS, I didn't actually run these scripts so there may be a typo or two that prevents them from running properly as is.

Solution 2 - Php

Sounds like the session cookie is set to be secure. Cookies have a "secure" flag which, if set to true, means that the cookie won't be sent to non-https sites. PHP is probably using that for its session cookies. You can change this with the session_set_cookie_params function, or with the session.cookie_secure setting in php.ini.

Solution 3 - Php

We had this issue as well. It turned out to be because we were using the suhosin patch on our PHP installation. We fix it by setting suhosin.session.cryptdocroot = Off in /etc/php.d/suhosin.ini.

For the suhosin manual about suhosin.session.cryptdocroot see http://www.hardened-php.net/suhosin/configuration.html#suhosin.session.cryptdocroot.

We originally found the fix from this blog post: http://www.yireo.com/blog/general-news/315-switch-between-http-and-https-looses-php-session.

Solution 4 - Php

The following solution assumes the secure and non-secure servers have access to the same backend services (cache, database store, etc).

We had to deal with this same issue when sending a user to our checkout flow when they were done shopping. To solve this, we put in place a caching layer and cached all the pertinent data. For example, we would glean the product ids and user id from the session values, serialize them, create a hash, and finally store the session data within cache using the hash as the key. We would then redirect user to the secure site with the hash in the url.

When the user ended up on the secure site we would attempt to pull the data out of cache based on the hash. Then with the user id and product ids we could load all the pricing and description data out of the database and present to the user for final checkout review.

There is an inherit risk in that the cache data is volatile, but we have never had any issues with it as the redirect happens quickly.

Solution 5 - Php

Looks like your session cookie is created with the secure flag, but there's something with the url of your checkout page due to which the session cookie isnt being passed over.

Or probably, your session cookie isnt secure - just that the url of the checkout page is different enough (http://mysite.com vs http://www.mysite.com) that the browser isnt sending the cookie.

If you'd like to read more on flipping over from http to https and vice versa - do take a look at at my writeup on selective ssl :-)

Solution 6 - Php

You can't pass session values between different domains. You must use http post-get or a database to pass your values. For security, you can concat all your values in a string and use

sha1($string)

and post it alongside your values and calculate the sha1 for the values other page gets, then compare the hashes.

Post method on different domains cause browsers to show a security message, so don't use that.

Using url for get method is not safe, you would need to ask for a password on the redirected page for allowing the get parameters in your system.

Do not use cookies if you need security.

The way I am suggesting is, save the values in a database and generate a key, then make your redirection link using your key, forward the users page with a get parameter which has the key, then the page user is redirected to gets that key, fetches the data and removes the key. you can generate a key with sha1

PAGE 1---
$key=sha1($allvalsconcat);
//insert your session values to a database also the key in a column
header("Location: page2.php?key=".$key);

PAGE 2---
// select from database where key=$_GET["key"];
// delete from table where key=$key

this is pretty secure.

the things that can happen: a script entering random values for the parameter "key" to make your website load the data into your memory?

This is not going to happen because you delete the entry after using it. Some common misconception is that get values are unsafe and should always be avoided.

you can set the table engine type to "memory" in mysql if you want performance perfection.

Solution 7 - Php

I'd recommend, in addition to what most have stated here about transferring encrypted information, looking at it the same as if you were transferring sensitive information through a 3rd party API. How do you know someone isn't spoofing the request? There are many protocols for truly confirming the authenticity of the request, depending on how sensitive your setup is. You're opening yourself up to accounts being compromised if you're not careful.

Even though it's on the same server, consider this:

When someone is following the link, form action, etc. that passes over the encrypted key, what would prevent someone from sniffing it BEFORE they get to the secured version of your site? If I were at a public WIFI spot, that wouldn't be too far-fetched. I could pretend to be your site, reroute requests to my own laptop, grab the token, and redirect the visitor back to where they came. They would assume it was a glitch, and would have no idea. Now I can login as them, and possibly go buy $10,000 worth of stuff with their credit card on file and ship it somewhere else. The degree of caution you take here should match the degree of sensitivity.

Also, make sure you expire your tokens (one use only, after X number of seconds, etc), but I would also consider using the Post-Redirect-Get pattern on both ends, i.e.:

Don't show the direct link on a page or in the form of the unsecured site, but show a link that will then redirect on the backend (and handle all the token/encryption stuff). When you arrive at the secured version, do the same (don't leave a "?token=asdfjalksfjla" parameter just sitting there in the URL; redirect it).

So, formal token-based systems were designed to solve this very problem, but implementing OAuth just for this might be overkill. Spend some time planning the potential vulnerabilities before executing. Just because it'd be really hard to guess the token doesn't mean it's impossible (or there couldn't be collisions, etc.), so plan accordingly.

You also might need a more sophisticated session management system than PHP's built-in handlers. I don't know if you can force PHP to continue a session across multiple visits (switching protocols is treated that way).

Solution 8 - Php

Think about using HTTPS for all pages, that's the easiest way to avoid this problem and it will improve the security of your site.

If SSL for all pages is not an option to you, then you could use this approach: Switching between HTTP and HTTPS pages with secure session-cookie. The idea behind is, that you leave the session cookie unsecure (and therefore available to HTTP and HTTPS pages), but have a second secure cookie to handle the authentication. It's a good way to separate the two concerns "maintaining the session" and "authentication".

Solution 9 - Php

You can manage session between HTTP to HTTPS or HTTPS to HTTP:

  1. Transmit session ID between page using GET

  2. POST session ID by POST

  3. Use files to save sessions

  4. Use Cookies for sessions

  5. Use database to save session

Below example can be used to transmit using GET….

File : http.php ……………

<?php

session_start();

$sessionID = session_id();

$_SESSION['demo'] = ‘Demo session between HTTP HTTPS’;

echo ‘<a href=”https://www.svnlabs.com/https.php?session=’.$sessionID.’”>Demo session from HTTP to HTTPS</a>’;

?>

File: https.php ……………

<?php

$sessionID = $_GET['session'];

session_id($sessionID);

session_start();

if (!empty($_SESSION['demo'])) {
echo $_SESSION['svnlabs'];
} else {
echo ‘Demo session failed’;
}

?>

IE7 : This page contains both secure and nonsecure items

You have to use relative path for all static resource on page like css, js, images, flash etc. to avoid IE message secure and nonsecure items…

IE Message IE Message

Solution 10 - Php

This may not be possible since the cookie seems to be getting lost. The browser you're using must think it's for a completely different domain.

What browser are you using specifically?

Solution 11 - Php

By default I would expect a browser to treat connections to http and https as completely different sessions. Although the convention is that http://someUrl/ and https://someUrl/ will point to the same page it isn't guaranteed. You could have completely different sites running on port 80 (http) and port 443 (https).

I don't know PHP, but generally I would not expect session variables to be freely available between secure and non-secure sessions e.g. I wouldn't expect the credit card number from my last checkout to be available to all the subsequent insecure pages I visit.

Forgive the non-authoritative answer but I thought I'd chuck in my 2c since there aren't many answers.

Solution 12 - Php

Do you have a dedicated IP? on some shared environments the https and the http are routed through different servers, so switching actually loses access to the cookies since they're on different domains.

solutions would be: dedicated ip

forcing https on all pages at all times

Solution 13 - Php

I had a similar problem, however, this solution was good for me, perhaps will help others in the future

add this in your php.ini

suhosin.session.cryptdocroot = Off

suhosin.cookie.cryptdocroot = Off

Solution 14 - Php

I have got a solution by this..Try it.

$_SESSION['test'] = 'test';
session_regenerate_id(true);

header("Location: /");// the header must be sent before session close
session_write_close(); // here you could also use exit();

Solution 15 - Php

I have had this issue moving from http to https and I was able to solve this issue changing the website URL from http://example.com to https://www.example.com

adding the www to the URL solved this issue for me.

Thanks.

Solution 16 - Php

Don't worry this is a normal behavior because HTTPS is meant to be secure and it is doing his part.

Below are some tricks through which you can maintain the session while switching from HTTP to HTTPS.

  1. Transmit session ID between page using GET

  2. POST session ID by POST

  3. Use files to save sessions

  4. Use Cookies for sessions

  5. Use database to save session

Hope you will get something through my reply.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAllanView Question on Stackoverflow
Solution 1 - PhpJacobView Answer on Stackoverflow
Solution 2 - PhpJW.View Answer on Stackoverflow
Solution 3 - PhpTomView Answer on Stackoverflow
Solution 4 - PhpMike PurcellView Answer on Stackoverflow
Solution 5 - PhpRaghuView Answer on Stackoverflow
Solution 6 - PhpUğur GümüşhanView Answer on Stackoverflow
Solution 7 - PhplandonsView Answer on Stackoverflow
Solution 8 - PhpmartinstoeckliView Answer on Stackoverflow
Solution 9 - PhpRohan PatilView Answer on Stackoverflow
Solution 10 - PhpAllain LalondeView Answer on Stackoverflow
Solution 11 - PhpcodybartfastView Answer on Stackoverflow
Solution 12 - PhpBrian BarrettView Answer on Stackoverflow
Solution 13 - PhpWillian SantanaView Answer on Stackoverflow
Solution 14 - PhpUWU_SANDUNView Answer on Stackoverflow
Solution 15 - PhpMidz ElwekilView Answer on Stackoverflow
Solution 16 - PhpSumair ZafarView Answer on Stackoverflow