symphonycms icon indicating copy to clipboard operation
symphonycms copied to clipboard

Core creates useles sessions

Open michael-e opened this issue 9 years ago • 36 comments

Current versions of Symphony create a lot of useless session rows in the database when XSRF protection is active and entries are posted in the backend. Session data look like:

sym-|a:1:{s:10:"xsrf-token";a:1:{s:27:"ZR7UtEtKQtgmWeXIkBJDnT1GDAw";i:1;}}

so they don't include a username.

I found that the issue was introduced by e530d0b8630483189ff56c03c1e6561a1e95dc1a ("Move all requires to a single autoload file").

michael-e avatar Jan 18 '15 17:01 michael-e

Do you have anymore details I can use to debug this? Nothing is jumping to mind about why that commit would be causing the issue. When you say entries are posted in the backend, do you mean with Events?

brendo avatar Jan 19 '15 10:01 brendo

No, no events. I am just editing an entry in the Symphony backend (Content > …). I also have no idea why this commit is the issue.

michael-e avatar Jan 19 '15 11:01 michael-e

Something is off here. To edit entries in the backend, you must be logged into Symphony. The username and passshould be stored in the same session as the XSRF!

brendo avatar Jan 19 '15 11:01 brendo

Yep, I did it like this:

  • delete all rows from the sessions table
  • log in to Symphony -> one session is created, as you mentioned above
  • edit an entry (just save it multiple times) -> useless sessions have been added

michael-e avatar Jan 19 '15 11:01 michael-e

So for some reason new XSRF tokens are generated, which are saved to new sessions.

michael-e avatar Jan 19 '15 11:01 michael-e

This is on integration right? Let me try and replay those steps and I'll what I get locally

brendo avatar Jan 19 '15 11:01 brendo

I just double-checked, again:

  • Check out e530d0b8630483189ff56c03c1e6561a1e95dc1a (or later): broken behaviour.
  • Check out one commit earlier (6d239fc7dd234d959b3c61017e264df074179458): everything OK.

michael-e avatar Jan 19 '15 11:01 michael-e

I'm using 29000892a2b8d972431a1832d27f82892fd08dc7 and everything is A-OK following your steps. My configuration just has enable_xsrf set to yes.

I think the key commit that is missing for your scenario is 1e41aab65c9631688ce78f1830c851db856462b2 which was made to close off #2174

brendo avatar Jan 19 '15 11:01 brendo

I even tried current integration. :-(

Ah, wait, I disabled some extensions now, and now it works fine. So I will try and find out which extension does it!

michael-e avatar Jan 19 '15 11:01 michael-e

Ah, wait, I disabled some extensions now, and now it works fine. So I will try and find out which extension does it!

Let me know!

brendo avatar Jan 19 '15 11:01 brendo

OK, here we go: Do you remember the problems I had with a special (private) extension when the autoloader was introduced? Because the extension is running background processes, I had to include the autoload logic, and you told me how to do it. So the background worker contains the following code:

// Is there vendor autoloader?
if (@file_exists(DOCROOT . '/vendor/autoload.php')) {
    require_once DOCROOT . '/vendor/autoload.php';
} else {
    require_once DOCROOT . '/symphony/lib/boot/autoload.php';
}

// Include the boot script:
require_once DOCROOT . '/symphony/lib/boot/bundle.php';

// Begin Symphony proper:
ob_start();
symphony('administration');
ob_end_clean();

This extension causes those useless sessions.

michael-e avatar Jan 19 '15 12:01 michael-e

Meanwhile I rolled back Symphony and the extension to see if this has always been a background process issue. The answer is no. With the old code there are no useless session created (and yes, I verified that the background process is indeed working in my test). At that point in time — before autoloading was implemented — the extension used the following code to implement a background worker:

// Include Symphony classes. Rather ugly, but this is the only way.
require_once(DOCROOT . '/symphony/lib/boot/bundle.php');
require_once(DOCROOT . '/symphony/lib/core/class.symphony.php');
require_once(DOCROOT . '/symphony/lib/core/class.administration.php');

$nothing = Administration::instance();

require_once(TOOLKIT . '/class.entrymanager.php');
require_once(TOOLKIT . '/class.sectionmanager.php');

@creativedutchmen, do you have any ideas why autoloading (as in the previous post) creates so many XSRF tokens/sessions? (Or why the old version did not? Or how to prevent this issue?)

michael-e avatar Jan 19 '15 13:01 michael-e

I assume that the old version of creating a Symphony object has worked for me because it simply didn't include all the Symphony files, and so (by chance) it didn't attempt to create/verify an XSRF token.

Using autoloader for a background process as mentioned here means that there will be "a complete Symphony" available for the background process, which also means that Symphony will attempt to create an XSRF token (because I configured this for the administration context a.k.a. backend).

@brendo, @creativedutchmen: Is this correct?

If yes, the question is: How could a background process (I also think about the Email Newsletter Manager) start Symphony preventing the generation of an XSRF token (which in turn will create a session)? Maybe we are missing an important feature here?

michael-e avatar Jan 23 '15 11:01 michael-e

@michael-e sorry, can't really take a real close look at this moment, I'll have some more free time in two weeks...

However, I do think you are on the right path. In the past only the files that were absolutely needed were included, but we are including a whole lot more now. However, I would think the empty session would not be written to the DB at all, is the function that cleans up the session called at all?

creativedutchmen avatar Jan 23 '15 11:01 creativedutchmen

Thanks for the pointers, I will do some more research. The cleanup function, however, will not see the sessions as empty (because they contain XSRF tokens).

michael-e avatar Jan 23 '15 11:01 michael-e

Ah yes, of course. If all else fails you can always empty the session, and then call the cleanup function yourself...

creativedutchmen avatar Jan 23 '15 11:01 creativedutchmen

Thanks a lot for this idea, it seems to be the simplest solution by far. I do it like this:

// Begin Symphony proper:
ob_start();
symphony('administration');
// If XSRF protection is used, a session will have been generated.
// Drop the useless session:
$_SESSION = array();
cleanup_session_cookies();
ob_end_clean();

@brendo: If you think that this is a "clean enough" solution for background workers, feel free to close this issue.

michael-e avatar Jan 23 '15 12:01 michael-e

Can't really help here, just curious...

Shouldn't the token only be created when someone logs into the backend?

jensscherbl avatar Jan 23 '15 14:01 jensscherbl

The backend process uses the administration "context", this is why it calls symphony('administration'). Poor Symphony can't know that it's not a human browser. :-)

michael-e avatar Jan 23 '15 14:01 michael-e

Ha, you mean only using it after login? Well, no, even the login form uses the XSRF token.

michael-e avatar Jan 23 '15 14:01 michael-e

Ha, you mean only using it after login?

Exactly.

Well, no, even the login form uses the XSRF token.

Does this make sense?

jensscherbl avatar Jan 23 '15 14:01 jensscherbl

Yes, in my understanding of XSRF it makes sense to protect the login form. I may be proven wrong though.

Still, you are right to a certain degree: Creating a Symphony object alone (without any pages being created) wouldn't need to create tokens and/or sessions. But I am afraid that is the way it is implemented. @brendo can probably explain it better than me. :-)

michael-e avatar Jan 23 '15 14:01 michael-e

Yes, in my understanding of XSRF it makes sense to protect the login form.

Yes it does!!!

Creating a Symphony object alone (without any pages being created) wouldn't need to create tokens and/or sessions.

I've played with this on my own and the closest thing I could do was to create my own Symphony class implementation. (i.e. not use the Administration class).

But yes, token/session should only be created when required, not always.

nitriques avatar Jan 23 '15 15:01 nitriques

Yes, in my understanding of XSRF it makes sense to protect the login form.

Yes it does!!!

Can someone explain this to me, please?

jensscherbl avatar Jan 23 '15 15:01 jensscherbl

Can someone explain this to me, please?

It does not. It simply does not make sense to protect the login page, as that would imply you know the login details. Which renders the entire attack superflous...

creativedutchmen avatar Jan 23 '15 15:01 creativedutchmen

Aha!

michael-e avatar Jan 23 '15 16:01 michael-e

It does not. It simply does not make sense to protect the login page, as that would imply you know the login details. Which renders the entire attack superflous...

I can post to the login form outside a browser. It forces the attacker to get a new token for each request, which makes brute force attacks less prone to succeed (because they are more time consuming)

nitriques avatar Jan 23 '15 17:01 nitriques

I can post to the login form outside a browser. It forces the attacker to get a new token for each request, which makes brute force attacks less prone to succeed (because they are more time consuming)

Makes sense, I guess. But our current implementation does only generate one token per session, so this only works if the session is destroyed on an unsuccessful login attempt.

jensscherbl avatar Jan 23 '15 18:01 jensscherbl

Anyway, this scenario has nothing to do with XSRF.

michael-e avatar Jan 23 '15 18:01 michael-e

this only works if the session is destroyed on an unsuccessful login attempt.

it should do that IMO.

Anyway, this scenario has nothing to do with XSRF.

I think it does. The whole point of XSRF token is to prevent Cross-site Request Forgery at large. Requesting a login is a request that can be forged.

nitriques avatar Jan 23 '15 18:01 nitriques