Tuesday, June 28, 2011

Secure way to recover lost password or user name

Most web applications that needs authentication has a common requirement which is the ability to recover lost password or user name. This has been discussed in many blog-posts before, for instance here.

In this post I'm presenting a secure way of revovering password using Context Framework and its key feature page scope. The goal is to make recovery resistant against data forging or data interception. That is, the system should resists false password recovery attempts or stealing victims emails.

In short, page scope is an exclusive data area on server that is unique to each opened page on user's web browser. That is even if same page is opened in multiple browser tabs the page scope is unique for each of them. Page scope is independent from session and does not use cookies. The security of the scope relies on random key (UUID) that is generated for each page.

In the scenario I have following assumptions:

  1. User has a user name and a password
  2. User has an email that she trusts and is registered to the system
  3. User has forgotten her credentials and needs reminder and if necessary a way to change password

In login page there exists a page component called Authenticator. It provides following features:

  1. A login with user name and password
  2. Credential revocation with email

If user finds herself in situation where she has forgotten her username, password or both she needs to user her email to recover them. The Authenticator contains two additional input fields (may be hidden at first). First one is for user's email address and second is for a security key for later use.

User enters her email and requests the Authenticator to send recovery email. The Authenticator receives the request and stores the email to page scope. To be more accurate the component itself is stored in the page scope, so storing the email is a simple as setting a class property.

Then the email is forwarded to Authentication service. The service then creates a random key, using for instance UUID. Then it checks whether the email exists in the system. If email is found the service sends a message to the email, containing the random key and informs that the key should be entered to another input in the page where the request was made.

If email is not found, then email simply contains information about that.

After sending the message, service returns the created key to the Authenticator. The key should be returned even if no proper email is found. In this way user cannot start guessing what emails might exist in the system.

Service could also send an exception or whatever error code. The important thing is that Authenticator must behave exactly the same as email would be valid.

Then what happens is that the Authenticator stores the key in to the page scope and begins to wait for the user to enter the key.

When user has received the email, she copies the key and enters it to the security key field. Authenticator receives it and checks that the entered key and the stored key match. If they don't an error message is shown. If they do, component knows that the email is valid.

The Authenticator then asks from Authentication service for the credentials that match the given email, and gets user name as return value. Then it displays the user name as plain text. If user is now able to remember her password, she simply logs in and everything is ready.

If she does not remember a password, Autheticator then shows an input field to create new password. The password can be checked for complexity etc. but in the end user sends a new password to server. The Authenticator receives it and asks the Authentication service to change password for the user name it received during recovery process.

After that user can be logged in automatically or require to login manually. At this point the process is ready.

Why is this scenario safe?


Email and security key are stored on server and they are not requested from user afterwards, so neither of them can be fabricated during later calls.

Also, intercepting request email is useless, because the random key is usable only on the page where the original request was sent.

Page scope lives only as long as the page is alive. As soon as page is unloaded or expires for some other reason, the security key is no longer usable at all.

Other Benefits


This scenario does not require any secret keys or hashes to ensure that requests are not forged. The contents of the sent email stays simple. Revocation process also do not require external pages to process it. Everything is handled on the same component. Process also does not need cookies because revocation is done outside of session.

This example demonstrates what benefits a stateful web framework has. It provides means to hide information form clients and store them on server so that information cannot be tampered with.

If you think that this scenario is unsafe, I would be happy to hear some comments.

In this Gist is a little snippet as Java-code to clarify what the component and service might look like. All templates and possible javascript-parts are exluded in the example.

Also check out the new features of Context that the 0.8.1 has to offer.

Update: 2011-06-29


I was given a comment on DZone that I should emphasize more that this has nothing to do with protecting entire session and that is true. This blog post concentrates only password recovery process where possible attacker might want to forge or circumvent the process some other way.

For example, an attacker might initiate password recovery with her own email, but forge later requests in such way that process continues with someone else's email or she could simply create a fake process altogether.

For protecting entire session and HTTP connection I recommend to to familiarize yourself with OWASP Top 10 risks and in this case session hijacking.

No comments:

Post a Comment