Security issue with login?

149 views
Skip to first unread message

Nico Haase

unread,
Sep 27, 2015, 12:39:34 PM9/27/15
to silverst...@googlegroups.com
Hi there,
please excuse that I send this bug report to the list without analyzing
the problem deeper on my own, but I'm some kind of "legacy admin" for
some Silverstripe projects and have only little time to help out. I sent
this report to the security list of Silverstripe twice (on August 23th
and 30th), but without any reaction, so I seek out for help over the
general developers list.

The following problem occurs: we have two completely seperated instances
of Silverstripe running on the same server, the one at www.domain/ and
another at www.domain/subproject. A user logging in at the one project
can also gain access at the other project if there is a user with the
same Member ID present. No further check is run.

I have an assumption about what is happening, but without any further
knowledge about where in the code this happens and how to fix it: is it
possible that only the user ID is stored in the server session, and this
is the only variable to be used to log someone in? So it could help to
use a second token either to identify the user with more data (use not
only the user ID, but also mail address); or we could store something in
the session to identify the Silverstripe instance the user ID belongs to.

The subproject is running 3.0.11, the main project 3.1.1. Yes, it is
unfair to not upgrade them first and see if this problem is solved, but
I do not have the time to do so and run all neccessary checks on both
projects. If you say this is fixed in a later version, I would schedule
a session with the new teams to update, but if not, I would do this
directly after a fix.

Regards
Nico

Patrick Nelson

unread,
Sep 28, 2015, 11:39:47 AM9/28/15
to silverst...@googlegroups.com
Quick question, to help verify if my theory is correct:

When you login to the root project "/" that logs you into the site at "/subproject" but not the other way around, correct? IMPORTANT: To test this, start out with a totally blank browser session via private browsing mode (e.g. chrome's incognito) and then login to the subproject, then go into the root site and see if you're logged in still.  If it's true that you're not logged in, it is because when you first login to the subproject, your cookies/session are isolated only to that sub-directory. However, once you go to the root site, that separate session cookie (with a "/" root path) ends up taking priority and will probably log you out or log you in with a different user (or whatever user is associated with the same ID as the user in the root site).

The root cause: Collision of both path ("/" also working for "/subproject") and cookie name (both are using "PHPSESSID").

Anyway -- I think the only way you're going to be able to get around this is to go about one of the following 3 possible solutions:
  1. Move the root site into a sub-directory that lives next door to "subproject" and not above it (so they set cookies separately instead of root overriding the subproject session cookies). This will prevent PHPSESSID from one project being sent to the other project erroneously, so they can maintain state separately.

  2. Setup "subproject" on a totally different domain (since the root site is already in the root, all cookies associated with it get set and are accessible in any sub-folder, which I think is your issue here). This gets around the issue the same way, since cookies are also isolated per-domain, not just per-directory.

  3. Modify the "inst_start()" method in the Session class in the SilverStripe framework to allow you to configure the actual session cookie name directly to prevent this collision, here: https://github.com/silverstripe/silverstripe-framework/blob/3.1/control/Session.php#L357
SIDE QUESTION (to other devs): What security value is added by changing the session cookie name to "SECSESSID"? I'm not sure this provides any value and, in fact, makes changes like these (which add security) more difficult since retention of this functionality would probably be hacky if someone tried to implement solution #3 above which, otherwise, would be pretty darned straight forward...

Hope this helps, Nico!

- Patrick


Nico

--
You received this message because you are subscribed to the Google Groups "SilverStripe Core Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to silverstripe-d...@googlegroups.com.
To post to this group, send email to silverst...@googlegroups.com.
Visit this group at http://groups.google.com/group/silverstripe-dev.
For more options, visit https://groups.google.com/d/optout.

Patrick Nelson

unread,
Sep 28, 2015, 1:13:08 PM9/28/15
to silverst...@googlegroups.com
Side note on the "SECSESSID" tangent: I thought about it a bit and I now recognize that it might have been an artifact of HTTP cookies being lost once going over SSL.  Looks like this commit changed all that: https://github.com/silverstripe/silverstripe-framework/commit/d629d9422fecb858fca53cbbb51ed0ef3d8cfa36

So, that may require deeper discussion over best practices and what to do in the context of a commonly used framework/CMS. If, for example, I user installs this CMS (using this framework) on a site which allows both secure/insecure connections and doesn't enable the "cookie_secure" option, yes they'll be exposed to accidentally sharing their session ID over an insecure channel and naturally will also not lose their session. If, however, they do have "cookie_secure" enabled, login over an insecure connection, they're still going to be exposed to possible session hijacking (as well as theft of credentials)

A better general solution to that would be to always redirect to an SSL connection immediately as soon as someone attempts to access the CMS, if enabled. In this case, the config could be called something along the lines of "Director.secure_base_url" and, in that case, maybe either deprecate or override "cookie_secure" to always being true if that URL is set and, naturally, have a validation error if "secure_base_url" is setup but doesn't start with the necessary https:// prefix. I've not thought about how you could handle dev/stage environments which may not have SSL at all. I'm used to Laravel's natural ability to configure per environment so I'm not sure how you'd do that here. 



Hamish Friedlander

unread,
Sep 28, 2015, 5:24:19 PM9/28/15
to silverst...@googlegroups.com
Hi,

Sorry we didn't respond to your initial security messages Nico - I don't actually see anything on the list at that time. Can you check what address you were emailing?

This isn't really a security issue. The fix is fairly simple - you need to either set http://php.net/manual/en/session.configuration.php#ini.session.save-path through your php.ini, or set Session::$session_store_path to be different for each site using eSilverStripe's configuration system.

You ideally shouldn't change the session cookie name (from PHPSESSID to something else), as this isn't as secure. Likewise, you should be setting session_store_path to different paths for each site even if they are in sibling directories (rather than parent / child).

Unfortunately we can't do this automatically in SilverStripe - we can't know a safe location to store sessions, as it's server dependant.

However, better than any of this is to have separate domains for each site. No matter what you do on the server side, the web is designed with the domain name being the security context, not the path. Having two separate sites with separate security contexts under the same domain but different paths is a bad idea for lots of reasons, and we can't fix that in code.

--- Technical details start ---

The key to PHP sessions is a large random number. If you have that number, you can access the session. 

The server generates this large random number and stores it in it's session store. Then it gives it to the client in a cookie. Because this number is random, no-one else can guess it. Because the traffic is only between client and server (and maybe encrypted, depending on risk profile), no-one else can see it. So that number is only known to a specific client & session store pair, and acts as a shared secret.

However it's important that I said "client" and "session store", not "user" and "website". When the client and the session store are both the same for two different user / website pairs, there's nothing that stops the client from using one shared secret with the other site. They just take the large number from the other site, pretend it's theirs, and the server looks it up, see's it's valid (because it's the same session store), and uses it.

By changing the session_store_path, you give each part of the website different session stores. Then if you try and use the large random number from one site with the other site, it won't find a session.

However you're still open to a lot of other non-session-store based attacks. For instance, because you're on the same domain, pages are allowed to see each other's content when iframed. So a malicious site on the same domain could iframe in the attacked site, and modify the content of the attacked site to perform an action (via an injected form or script). The browser will allow this attack request to use the correct credentials of the attacked site.

In other words, the only secure way to run multiple sites (SilverStripe or anything else) is to run them on separate domains.

A note on SECSESSID - SECSESSID was not really introduced to avoid losing your session, it was to separate the "insecure" session from the "secure" session. It is up to the developer to not do things that rely on strong session guarantees when using the insecure session. For instance, as you mentioned Patrick, it's important to redirect to HTTPS on attempts to log in. HSTS headers would be good here too. We could probably improve how this is warned against (throw an error if you try and store the Member ID in the session while on HTTP).

(It's easy to have environment specific config, both through the configuration system and Director::isLive code checks)

Hamish Friedlander | CTO
SilverStripe
http://www.silverstripe.com/

Reply all
Reply to author
Forward
0 new messages