Hi There,

I've stumbled across a problem with a shopping cart I've recently developed. It basically works by snatching the users session_id(), storing that in a MySQL Database, along with the product they add to the cart.

ie.

<?php

session_start();

$sessid = session_id();

...

$sql = "INSERT INTO carttemp SET
session_id = '$sessid', 
item_id = '$id',
item_size = '$size',
item_quantity = '$quanity";

...?>

When it comes times for the user to checkout, they get transferred to a secure HTTPS connection. The customer is then provided with a run down of what's in their cart - with code as simple as:

<?php

session_start();

$sessid = session_id();

$query = "SELECT * FROM carttemp WHERE session_id = '$sessid'";

...?>

As you can see the reference point is always the session_id There are no variables stored in sessions, I am simply using the session_id to match the data stored in the temporary database with the user.

90 % of the time this code works fine.

However, I have had a few reports that customers will add items to their cart, click on order (which changes them to HTTPS connection) and suddenly their cart will be empty! I've been able to replicate this problem, but only using Firefox 1.5 on PC and only sometimes (very strange!!) In these cases, it would appear that changing from HTTP to HTTPS generates a new session_id . Most of the time the session_id remains the same whether in HTTP or HTTPS, and you can jump back and forward, without dramas.

Does anyone know why this would be working sometimes, but not all the time, and how I can best avoid it from happening all together? Keeping in mind that onces in HTTPS, the user might jump back to HTTP and vice versa - the whole time I will need some sort of reference point to match items stored in the cart database with the customer who put them there!

Can I store the session_id in a cookie that can be accessed in both HTTP and HTTPS? And how would I reference and make sure I'm getting the right cookie without being able to use the session_id ? Or can I simply just scrap sessions and use cookies all together? There will be no sensitive date (well no data at all really) stored in the cookie, it is simply a means of linking a customer to their products whilst they are still browsing/ordering.

Or is there a way to simply maintain the session_id between HTTP and HTTPS? I would prefer to avoid a solution that requires the SID be sent through URL, POST or GET, as it would require huge amounts of re-coding.

Thanks in advances for anyone that can help me out with this situation!

Dogen

    Your solution is simple:

    1. Ensure that there is one and exactly one host name that can be used to access your web site. If there are others, make them redirect to the one true name (this includes www.example.com vs example.com - choose ONE). Make sure that nobody accesses the site by IP address either.

    2. Make sure that the HTTPS site operates on, and only on, the one true DNS name for your site. Have any page which links (or redirects) to the HTTPS site, use the one true name and vice versa for HTTP.

    3. Set the cookies with that one true domain name as their domain.

    Then it should all work.

    Of course I'm assuming you are using cookies for your sessions, but you absolutely must. I mean, you MUST not allow session IDs in the URL, as that is incredibly insecure - set session.use_only_cookies to ensure this.

    Anyway, this is what we do, and it works perfectly.

    The only difference is, I also set the secure=1 property on the authentication cookie for my admin users, and insist that they use HTTPS throughout their session. My normal users I only use HTTPS for pages which prompt for or contain personal details (e.g. delivery details, credit card, order history)

    Mark

      MarkR wrote:

      Your solution is simple:

      1. Ensure that there is one and exactly one host name that can be used to access your web site. If there are others, make them redirect to the one true name (this includes www.example.com vs example.com - choose ONE).

      Thanks Mark. I'm pretty sure this is the root of the problem. People are accessing the site via http://example.com rather than http://www.example.com - then when clicking on CHECKOUT they are taken unconditionally to https://www.example.com

      (Interesting to note that the above actions only cause a new session is Firefox 1.5! Even IE6 keeps the same session ID between http://example.com, https://www.example.com)

      However, a lot of people will be running that browser, so a redirect is definitely in order!

      MarkR wrote:

      The only difference is, I also set the secure=1 property on the authentication cookie for my admin users, and insist that they use HTTPS throughout their session. My normal users I only use HTTPS for pages which prompt for or contain personal details (e.g. delivery details, credit card, order history)

      Pretty much the same situation. I don't want normal users to be restricted to HTTPS as they need to browse via HTTP to add goods to the cart etc. but then when they hit checkout it takes them to HTTPS.... they might always want to change whats in their cart once they find out postage values, in which case they'll jump back to HTTP and then return to HTTPS when they go back to checking out.

      I'll start storing the session id in cookies and access it via the forced true domain name and that should fix things!

      Thanks again!

        8 days later

        Just wandering if anyone has any suggestions on how to enforce views to browse the website via www.mysite.com rather than mysite.com? (whether in HTTP or HTTPS)

        Cheers

          Create a .htaccess file and add these lines (domain.com is your domain, PLEASE DO NOT REMOVE THE "\" before the dot on the third line !!!

          Options +FollowSymLinks
          RewriteEngine on
          RewriteCond %{HTTP_HOST} ^domain\.com
          RewriteRule ^(.*)$ http://www.domain.com/$1 [R=permanent,L] 
          

            I believe you could set the session.cookie_domain in your php.ini or a .htaccess file to ".example.com" (note the leading period) so that any sub-domain -- or no sub-domain -- will be accepted.

              There is no need to use mod_rewrite to redirect a whole domain. If using Apache, do:

              <VirtualHost *:80>
                ServerName example.com
                ServerAlias foo.example.com
                DocumentRoot /var/empty
                Redirect permanent / http://www.example.com/
              </VirtualHost>
              

              Which would redirect example.com and foo.example.com to www.example.com (Assuming those DNS records existed and pointed at your server)

              Mark

                Write a Reply...