Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Security loophole around password changes with .NET FormsAuthentication and persistent cookies?

OK, here's a scenario:

  1. Bob logs into mysite.com, which uses .NET forms authentication, and ticks 'remember me'.
  2. Eve steals Bob's laptop
  3. Bob gets a new laptop, and changes his password.

Now at this point, Eve has a stolen laptop, which has a persistent cookie stored on it, that will log her in to mysite.com as Bob - and, as far as I can tell, this will work even after Bob has changed his password.

By default, the forms authentication cookie doesn't contain Bob's password (whether plaintext, hashed, or otherwise encrypted) - so Bob's password isn't involved in the cookie authentication process at all, and the same username that worked last week will still work today.

It's an easy enough loophole to work around - by simply setting FormsAuthentication.SetAuthCookie("username:passwordHash") or something and then decrypting and splitting the cookie in your authentication handler - but I have trouble believing this issue exists 'out of the box'... am I missing something?

EDIT: Note that I'm assuming here that the purpose of a "remember me" button is to stop you having to enter your password every time you visit a website. This works on Facebook, Twitter, Gmail, and practically every other website I can think of - and I'd be very surprised if this isn't the purpose of the 'persistent cookie' option in .NET FormsAuthentication.

Also, yes, I accept that performing two-factor authentication on every incoming request incurs a certain overhead, but in real terms it's only marginally more expensive than retrieving the user from the database based on their username, which you'd probably be doing anyway.

EDIT 2: It appears that at least one major .NET site - CodePlex.com - is vulnerable to this; see http://codeplex.codeplex.com/discussions/350646

like image 257
Dylan Beattie Avatar asked Mar 30 '12 13:03

Dylan Beattie


2 Answers

Perhaps it would make sense to only accept FormsAuth tickets issued after your last password reset.

So in Global.asax AuthenticateRequest, extract the FormsAuthenticationTicket.IssueDate from the encrypted ticket, and compare it to the date of that users last password reset (you would need to store this in your database when they reset their password).

If the ticket was issued before that date, then reject the ticket, do not authenticate them and ask them to login in again.

I haven't implemented this myself, so I could be missing a hole in the theory somewhere...

like image 124
JonoW Avatar answered Nov 16 '22 00:11

JonoW


Having a hashed password in the authentication cookie would mean that you have to check it upon every request. This would be inefficient as authentication can be costly.

You could provide an easy "fix" for your concern involving an id in forms cookie user data section. Note that if you create the cookie on your own, you can inject an arbitrary data there, for example the password's record id.

Now, you could add the AuthenticateRequest handler in your global.asax. You try to retrieve the user data from the cookie and you compare the id retrieved form the cookie with the one in the database. If they do not match, you return an error and/or log the user out of the application.

like image 25
Wiktor Zychla Avatar answered Nov 16 '22 02:11

Wiktor Zychla