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.

Version 0.8.1 released

0.8.1


Calling javascript-functions


Previously remote javascript had to be done using RemoteCallBuilder that was injected to component. This was a bit cumbersome approach.

The RemoteCallBuilder is now removed and replaced with new annotation @ScriptElement that can be used for properties or method return values. To incorporate that three classes were introduced, Script, FunctionCall and ComponentFunctionCall.

Speed enchancements


During buildphase a complex metamodel is created from each component. This was refactored to more efficient model, which reduced the number of checks and other Map-accesses to minimum.

Resource cleaning enhancements


Previously, in development mode, during each page access all resources were reloaded to reflect possible changes which was wasting cpu-power. Now resources are reloaded only when something really changes and speeds up the system.

XSL-post processing


Because templates are XSL-based they can be modified programmatically. For that a XSL-postprocessing feature was added which enables the XSL be modified and also meta-data can be read.

0.8.0


Package and class refactoring


This version has two main functions. First it was a big refactoring version where packages and class names were refactored to be more conicse. Also System configuration model was modified to compeletely different.

Resource loading from components


This version also added a possibility to return resources from components. They can be used to return for instance JSON for javascript handling or for example images or PDF-files for other purposes.

Server push/Comet/delayed updates


In this version I finally managed to create a model which enables to use long polling as a kind of server push. From the framework point of view it is called delayed method call.

Context does not itself provide any comet-handling because it is dependent on web container. It has been tested with Jetty continuations but should be compatible with other types too.

Page flow filter


Because Context is highly stateful and each page call consumes some memory it is possible to exhaust server memory with enough calls. For this I added a page flow filter that can be used to throttle the amount of calls if necessary.

Integration with JRebel


Currently web development using JRebel is quite convinient. In development mode there is practically no need to restart server with few exceptions.

  1. New views and URL changes: When new view is added or view url is changed it is required to restart server because it is currently impossible to reload servlets in Guice Servlet.
  2. Singleton scoped entities: There does not exists a good Guice plugin in JRebel and if Guice managed entities have dependency changes they are not reloaded automatically.

For more information visit www.contextfw.net.