Usage scenario:
A online shop that allows users to buy products without having to register for an account.
The user browses products, adds products to the cart and does an checkout. Browsing works over http - the checkout uses https.

After the customer has done the checkout he continues browsing and then wants to buy another product, but as soon as he tries to enter the checkout the cart (session) is lost.

Technical scenario:
The user switches several times between http and https. With the current implementation of the session handling this isn't not supported.
We end up with a "duplicated" entry in the sessions table.
I think this post is about the same scenario: http://drupal.org/node/575280#comment-3694746
Solutions?
Use the same session content for http and https?
On a step up from http to https this seems not to be a big problem, but what is with a step down from https to http?
The session contents could be security (permission) relevant.
Would this approach open a new attack vector?
When do we have to do a session regenerate to prevent the possibility of session hijacking?



Changes in the attached patch:

  • Use only the sid as key on http connections. This prevents a duplicated session when stepping down from https to http.
  • On initially stepping up from http to https use only the sid as key since ssid doesn't exist in the table. But make sure the ssid is saved.
    This code needs definitely a review - I don't like how I've to check if it's an initial step up :|
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

das-peter’s picture

Quote from DamZ answer on my mail (thanks for your fast response :) )

My feeling is that we are missing a session_regenerate() in _session_read() when we detect a HTTP to HTTPS migration (the if (!$user) part).
Not sure it will be enough to do the trick, but it seems clear that we want to generate a new secure cookie at that precise moment.

Note that the current tests we have work because we are testing:

  • start a session in HTTP
  • login in HTTPs
  • verify that the session data has been carried over.

... and the login triggers a session regeneration.

Damien Tournoud’s picture

Version: 7.0 » 8.x-dev
Priority: Normal » Major

Mixed session support seems totally broken right now when mixed HTTP/HTTPS mode is used. Bumping to major, and assigning to 8.x as it needs to be fixed there first.

das-peter’s picture

Definitions:

Glossary:
  • step-up: The switch to a higher security level. E.g a login or change from http to https.
  • step-down: The switch to a lower security level. E.g a logout or change from https to http.
  • Cookie "http-only": Browser disallows JavaScript the access to the cookie.
  • Cookie "secure-only": Browser sends cookie only over a secure connection (https).
Attacking-Vectors:
  • session-fixation: Victim is forced to use a known session id.
  • session-hijacking: Steal the victim's session id.
  • man-in-the-middle: Scan the http-traffic to get sensitive data (e.g credentials or session id).
  • XSS: Inject code into the target site to fetch or set data (e.g session id). A session-hijacking shouldn't be possible since the session cookie should be "http-only".
Countermeasures:
  • session id regeneration: Makes sure the session id can't be set by an attacker - used on "step-up". Doesn't prevent session hijacking (e.g. by a man-in-the-middle). The session could be hijacked after the "step-up".
  • store client specific data in the session to identify its owner: Can massively increase the complexity for a session hijacking, but likely introduces issues like session drops.
  • https: Prevents man-in-the-middle attacks and session-hijacking (but only with a "secure-only" session cookie).

Modes:

  • http only
    Session / login is available only over the http protocol.
  • https only
    Session / login is available only over the https protocol.
  • mixed mode
    Session / login is available over the http & https protocol.
    • single session
      The http / https sessions stand on their own. This is a likely scenario if the site provides a member area (http) but the administration is only reachable over https.
    • shared session
      The http / https session is shared. This is a likely scenario for a shop site where the user adds items to a cart over https but the checkout runs over https.
      One point to care about is that a hijacked http session is not enough to gain access with the https session. Another topic is how to ensure that some areas / privileges are usable over https only. Since the session is shared the http session of an administrator will have the same privileges as the https session.
Pisco’s picture

There is one, probably additional, scenario I'd like to point out. When a user logs in coming from a direct link, possibly a bookmark to https://example.org/user/login, and from there continues browsing the site over http: Unless Drupal sets both session ids (sid and ssid) the user will loose his session right after the login (step-down)!

You may want to read some interesting sources on the topic:

On a side note: for all this to make sense, it's absolutely crucial for site builders to ensure that confidential is sent and accessed exclusively over https!

Akaoni’s picture

@das-peter:

Use the same session content for http and https?

This would create an attack vector. Consider the following scenerio:

  1. User browses and adds products to cart via HTTP.
  2. User fills out personal and payment details in checkout via HTTPS (session step-up).
  3. User realises they have forgotten something. Goes back and browses and adds more products to cart via HTTP (session step-down).

Because the session content is shared, the checkout personal and payment details could be hijacked in step 3.

@Pisco: Similarly, solving the issue you pointed out would open the user's session to being hijacked if it was stepped-down to HTTP.

@DamZ: Totally agree that Drupal needs to continue the session when a user switches from HTTP to HTTPS. Disagree that the session needs to be regenerated. This wouldn't fix the above issue however, so will raise/discuss this as a seperate bug.

Suggestions

Enough negativity, here's my thoughts on some solutions.

Quick solution:

Get the online shop system to destroy both the HTTP and HTTPS session on successful checkout. This will clear the cart and checkout info plus allow any new HTTP sessions to step-up to HTTPS. This would not work for the scenerio I outlined about as if the user added items to the HTTP session after the HTTPS was created it would not update the HTTPS session.

Better solution:

Use both the HTTP and HTTPS sessions to store different data (ie. cart contents in HTTP, checkout contents in HTTPS). This would solve some issues (eg. cart would persist across HTTP and HTTPS) but not others (eg. user would only be logged in for HTTPS). This would also be very complicated having to code which data goes where.

Ideal solution:

As soon as a session is stepped-up to HTTPS, enforce HTTPS. Redirect any HTTP requests back to HTTPS to ensure that the session contents (login, cart, checkout info etc.) are available to the user while still keeping them safe from hijacking. This would need to be done by an HTTP session (or cookie) flag that says an HTTPS session exists.

Pisco’s picture

Thanks for pointing that out @Akaoni. In my understanding, a correct step-up does not open any security holes. As soon as the user tries to log-in or register, Drupal should enforce a secure connection. From then on, the user is required to use the secure connection until the session in closed, just as you describe in Ideal solution. @das-peter already mentioned that One point to care about is that a hijacked http session is not enough to gain access with the https session. The solution is not to allow http, that is to enforce https, once as a secure session has been established. A step-down should only be possible with logout (i.e. the termination of a given secure session).

It is of uttermost importance, that secure sessions use Cookies with the secure flag on!

I think this is something that should be fixed asap on drupal.org too: a user should in any case be required to transmit his credentials over a secure connection, and authenticated and authorized sessions should be secured for as long as they last.

sun’s picture

Akaoni’s picture

Thanks, sun. ;)

Tested the issue mentioned above and it seems it would indeed fix the problem (akin to the Quick solution). It still won't hijack proof your site, but it is an improvement on current Drupal functionality.

das-peter’s picture

Changed patch to keep users always on https if the stepped up once in the same session as mentioned by Pisco.
The session sync for the step-up currently works - if necessary I'll combine this patch with the one from grendzy in #1050746: HTTPS sessions not working in all cases.

Anonymous’s picture

Status: Active » Needs review

Status: Needs review » Needs work

The last submitted patch, drupal-session-handling-https-step-down-support-1131986-9.patch, failed testing.

das-peter’s picture

Status: Needs work » Needs review
FileSize
3.48 KB

*yay* someone is interested in this issue - here comes the re-roll.
Fixed path prefix and re-rolled against D8.

Status: Needs review » Needs work

The last submitted patch, drupal-session-handling-https-step-down-support-1131986-12.patch, failed testing.

magnusk’s picture

Requiring https for the rest of a session (i.e. preventing any step-down except via logout) seems excessive in a basic scenario (login and account edit over https, everything else over http). Forcing https for every single server request seems rather resource-intensive (e.g. process under Apache) if all one really wanted was to secure the login and account edit pages.

Why would the approach described at https://github.com/blog/737-sidejack-prevention not be good enough in the above scenario? in many cases a site could tolerate potential sidejacking of an account that lets someone else manage to post content or comment under one's identity, but as long as the account itself cannot be stolen it would be good enough? possibly a somewhat more elaborate scenario would be to half-step up and require password entry if the user wants to create or edit a node (similar to what Amazon does when you go from product browsing and cart management, to payment or account management?).

Pisco’s picture

Hi magnusk, requiring encryption for the rest of a session is the only truly secure approach. If you have read the whole thread you may have noticed that I already linked to the blog post on GitHub, and even their follow-ups. You may also have noticed that the in the blog post you mentioned, Ryan Tomayko pointed out that “The only way to protect yourself on every site you visit is to secure and encrypt your connection for all requests.”

Security in this case is a binary thing, either it's secure, or it's not. They only way to provide (true) security for your customers, is to serve all request encrypted from the moment the user logs in, to the moment the user logs out. That's why GitHub went SSL Everywhere, and even serves SSL Proxied Assets.

magnusk’s picture

Thanks Pisco. I understand... but have a feeling that there are types of sites or interactions where it is not necessary to always use https. For instance, I don't really care if someone could hypothetically manage to hijack one of my Amazon.com sessions and add stuff to the shopping cart -- they won't be able to checkout without a step-up and my password. Secure connections are necessities in certain conditions, but could it be restricted to certain pages if limited potential damage can be tolerated? again I like to use Amazon as an example of an e-commerce site that doesn't use https for all pages and still we don't hear of or worry about all sorts of account robberies on their system, do we? how is their approach reliable without always using https?

Pisco’s picture

Hi magnusk, I think you're right. There is a very important difference between Amazon and Drupal that you have to consider. Amazon is a very dedicated application where the engineers know exactly which actions require a fully logged in (authenticated and authorized) user, they can tweak their app to their specific needs. Drupal on the other hand is a very general framework where authorization (permissions) is tightly coupled to authentication (authenticated user login). To achieve what you describe, Drupal would need a mechanism that enables it to know which actions require a secure session.

Imagine a view that shows content from different nodes, some of that content is sensitive. To achieve what you describe, Drupal would have to distinguish 3 cases to be able to decide what can be shown, and what not:

  • anonymous user
  • logged in user
  • logged in user with secure session

I think this would make things unnecessarily complicated and komplex, without giving any advantage in a general use case.

Besides, I think that the computing power required to encrypt responses through SSL as compared to without encryption, can be neglected. Also read HTTP vs HTTPS performance. I'd love to see some statistics for Drupal.

bak’s picture

Hi. I've configured for last two days mixed mode for my site and I have the following thoughts:

  1. Session handling for the HTTP/HTTPS mixed mode in Drupal it's a mess - definitely it should be fixed in core.
  2. The mixed mode is the most flexible option because many sites have free/open/insensitive content as well as paid/dedicated/sensitive content and switching between HTTP and HTTPS in my opinion is a must.
  3. Applying the HTTPS for the free/open/insensitive content is expensive, esspecialy if the insensitive content generates heavier load than the sensitive content - in such case HTTPS for free/open/insensitive content is a waste.
  4. The sensitive content should be covered by HTTPS for whole user activity on the site - should be a flag which will determine the secure context (storing in the secure session) when an object is added to the session.
  5. Drupal should handle the HTTP/HTTPS switching for insensitive part of the session (i.e. messages) - I've found the "registration issue": annonymous(http) goes through registration(https) where is generating the "Check your email ..." message (and is storing in the secure session, I guess) and after registration the registrant is redirected to any page (http) and doesn't see the message (doesn't know, to check e-mail!). New user will see the "Check your email ..." after clicking on the confirmation link (https) in the email - a little bit to late!
Akaoni’s picture

Status: Needs work » Needs review
FileSize
13.74 KB

Here's a D8 reroll of a full session rebuild I did for one of my sites.

With mixed mode turned on, it allows any session data set in HTTP to be shared with HTTPS. As soon as session data is set while in HTTPS, HTTPS is then enforced for the rest of the session. Also, I'm a firm believer that session != login, so session data persists throughout logins.

With mixed mode turned off it should function as it does now (no session sharing).

Hope this is helpful!!

CNR to run the patch through QA.

Status: Needs review » Needs work

The last submitted patch, core-session_rebuild-1131986-19.patch, failed testing.

greggles’s picture

So there are some test failures we might expect in session handling and https session handling, but also in node administration and (our favorite) poll module!

Akaoni’s picture

Status: Needs work » Needs review
Issue tags: -ssl, -https, -session, -Needs backport to D7

Status: Needs review » Needs work
Issue tags: +ssl, +https, +session, +Needs backport to D7

The last submitted patch, core-session_rebuild-1131986-19.patch, failed testing.

ice5nake’s picture

This problem exists in D6 too. But I currently can only make switches between http and https break sessions in IE9. The switching works for me in Win FireFox 7, Win Chrome 16, and Mac Safari 5.1.

So does anyone know how session_id values get generated under the hood in PHP? When using the default settings? I suspect that IE9 breaks because IE9 reports a different _SERVER["HTTP_USER_AGENT"] between HTTPS and HTTP. I suspect that the user agent is used in generating the session id.

I tried changing the session.hash_function php.ini setting and it only seemed to make a difference in Win Chrome 16.

das-peter’s picture

@ice5nake The session id is random - it has to not rely on any data from the client side. If something fails on only one specific browser, it's likely it has to do with the cookie handling.

ice5nake’s picture

@das-peter, Thanks.

I found the code for php_session_create_id http://svn.php.net/viewvc/php/php-src/tags/php_5_3_8/ext/session/session...

IE9 is sending back separate cookies for HTTP and HTTPS. Even the Google Analytic Cookies are different.

FireFox is sending back separate cookies for HTTP and HTTPS, but only when I am logged out of Drupal. When I log in they are unified to both use the HTTP sid

Another thing I am seeing is the same sid is popping up on different browsers. This seems strange to me.

grendzy’s picture

I just found this, and haven't read all the comments in detail, but can someone clarify why it isn't a duplicate of #1050746: HTTPS sessions not working in all cases?

das-peter’s picture

This issue is more about security implications (session hijacking) than about getting the http/https session to work together.
But a side effect of the work on this was also to care about the other issue.
The relation to #1050746: HTTPS sessions not working in all cases is mentioned several times here - but since the scope was different the issues weren't merged.
I'm not sure how to proceed - suggestions welcome.

Btw. for me it would make sense to add a setting to allow users to define if a step down from https is allowed or not. The default should deny a step down to provide the most secure setup by default.

lpeabody’s picture

Have to agree with das-peter on this. The most obvious and commonsensical way forward at this point without significant re-write while having the greatest positive impact on security would be to just add a setting that specifies if a step-down is allowed or not after establishing an HTTPS session. In my particular setup this would be the ideal scenario. It becomes an argument about performance impact, but I can easily mitigate that by bumping up the allocated resources available to the virtual machine (ESX ftw). I'm not saying that everyone is in my position, I'm just presenting a particular use case.

Great thread to read by the way.

bibo’s picture

This is currently set for D8. What I've read so far seems to imply that D7 cannot handle switching between http & https either?
So we can not just make one page https and the rest http? I truly hope I've misunderstood.

das-peter’s picture

@bibo: Well you can have http & https pages with Secure Pages or by setting up the required rewrite rules in the host configuration.
Currently the pitfall is the session sharing between http & https - but please take a look at the project page, there's a list with known issues.

martin107’s picture

Issue tags: +Needs reroll
Berdir’s picture

Version: 8.0.x-dev » 7.x-dev

8.x now longer supports mixed session mode, so I think this can be moved back to 7.x ?