What's new? | Help | Directory | Sign in
Google
google-web-toolkit-incubator
Likely additions to Google Web Toolkit
  
  
  
  
    
Search
for
Updated Oct 31, 2007 by reinierz
Labels: Type-FAQ
LoginSecurityFAQ  
Explains how to do logins with GWT in a secure fashion.

This FAQ page is slightly more hands-on, but you should definitely also read Security for GWT applications.

Login Security

This article describes how to do the following:

Creating a 'login' page

A login page is consists really of just a TextBox for the username or email address or other identifier (henceforth known as username, and a PasswordTextBox for the password.

Add a 'login' button to the mix and that's all there's to it. This login button will result in an AJAX call to your server, using either JSON over RequestBuilder or GWT-RPC.

Your server will then validate this login, and return a sessionID to your GWT app. The GWT app will store this sessionID in a static field. For every further request your GWT app makes to your server, include this sessionID in the payload of the request. (Either in the JSON data or the object you are transferring using GWT-RPC).

NB: Do NOT attempt to use the Cookie header to transfer the sessionID from GWT to the server; it is fraught with security issues that will become clear in the rest of this article. You MUST transfer the sessionID in the payload of the request. For an example of why this can fail, see CrossSiteRequestForgery.

Storing user/pass info on the server

During account registration (or a change password operation), your user will specify a username and a password that he'd like to use. You'll need to store this information on your server somehow so that you can authenticate future login requests. However, storing the passwords without encryption on your server means that losing your database, or a compromised server, will result in your user's passwords being out on the street. The vast majority of users 're-use' their passwords, which means virtually their entire online existence is at risk. This is irresponsible, not to mention the bad press such a breach would generate.

Fortunately there are ways to 'mangle' the password so that you can still authenticate users, but without storing the password itself. This act is called hashing.

The basic mathematical principle behind hashing is explained on this wikipedia page, but all you really need to know is:

Use BCrypt. It's a very simple algorithm available for a number of platforms that takes a password and converts it into a string which can be used to ascertain that someone knows the password without actually storing the password. It's specifically written for login authentication and security experts have thoroughly reviewed it.

So, whenever a user registers or changes a password, send the password to your server as usual, but then let your server BCrypt the content. Then, when a user logs in, simply ask the BCrypt framework to check if the password entered is validated by the hash that you stored in e.g. a database.

Add new account to database example for java using jBCrypt:

    String password = /*(get password from incoming JSON or GWT-RPC request)*/;
    String hash = BCrypt.hashpw(password, BCrypt.genSalt());
    //(create new user entry in db storing ONLY username and hash, *NOT* the password).

Check if an incoming user/pass combo is valid for java using jBCrypt:

    String password = /*(get password from incoming JSON or GWT-RPC request)*/;
    String hashFromDB = /*(obtain hash from user's db entry)*/;
    boolean valid = BCrypt.checkpw(password, hashFromDB);
    if ( valid ) generateSessionIDAndSendItBackToClient();
    else sendErrorToClient("Wrong Username or Password.");

BCrypt is similarly trivial to use for the other languages.

How to remember logins

Our login system so far misses a useful feature: For now it requires users to log in again every time.

We can use Cookies to allow the user's web browser to 'remember' the login. In GWT, to set the cookie (which you'd do right after your GWT code receives the response as we did in the previous code fragment):

    String sessionID = /*(Get sessionID from server's response to your login request.)*/;
    final long DURATION = 1000 * 60 * 60 * 24 * 14; //duration remembering login. 2 weeks in this example.
    Date expires = new Date(System.currentTimeMillis() + DURATION);
    Cookies.setCookie("sid", sessionID, expires, null, "/", false);

Now you can run the following code right after your !EntryPoint begins execution:

    String sessionID = Cookies.getCookie("sid");
    if ( sessionID != null ) checkWithServerIfSessionIdIsStillLegal();
    else displayLoginBox();

Remember - you must never rely on the sessionID sent to your server in the cookie header ; look only at the sessionID that your GWT app sends explicitly in the payload of messages to your server.

auto-complete and GWT

Certain browsers offer the option to store username/password combinations so that they are automatically filled in for the user the next time they visit the page. However, usually this works only if there are two input boxes (one of type password), and only if those input boxes are loaded along with the main page, and not added later via javascript (which is what GWT does).

In order to force these input boxes to show up, stuff them in the project's HTML in an invisible div. Then, in GWT, instead of creating a TextBox and a PasswordTextBox, make the div visible and read out the values using the DOM. library.

TODO: Expand on this section.

Using Acegi with GWT

Acegi is a security system for Spring, but it can also be used separately. Bruno Marchesson wrote an article about it: Using Acegi with GWT.

Extra Security Discussion

Based on a chat with GWT's Bob Vawter

See http://groups.google.com/group/Google-Web-Toolkit/browse_thread/thread/59f3aafcf4951523

TODO: Explain how without https security is limited regardless, touch on bobv's proposal for running login outside of GWT over HTTPS, setting a (non-secure) cookie with a key, redirecting to a non-https GWT app which reads the cookie again, and then using a JS version of e.g. bcrypt or some other hasher to generate fresh hash values for every request, involving a counter so that the server knows which hashes have been 'used' - to protect against replay attacks. The highlights of this are discussed here


Comment by karajdaar, Nov 12, 2007
Comment by dao.hodac, Nov 20, 2007

thank's for those tips.

However, can you give us the generateSessionIDAndSendItBackToClient() function? what do you embed within SessionId? structure? If the server starts again, the sessionIds are lost?

how do you pass the password as encrypted to the server?

Comment by dao.hodac, Nov 26, 2007

hello, gensalt needs a log_round. what is it?

what do I have to set?

Comment by Vitaly.Sazanovich, Jan 21, 2008

>auto-complete and GWT:make the div visible and read out the values using the DOM Does that mean that we can't display login dialog in some fancy gwt way and should stick to the good old html if we want to use 'remember me' feature?

Comment by ruslanv, Jun 06, 2008

I recently started using GWT and was very surprised to see advice of sending token with each RPC call. Sending token in each RPC call doesn't look like efficient idea when JSP App Servers (Tomcat in my case) have pretty powerful concept of Sessions. So why would I invent wheel again ? It's unclear for me.

Comment by paulsschwarz, Jun 23, 2008

I understand that you don't want to use the sessionID that is sitting in the HTTP header for security reasons so you'd have this in the payload of the GWT-RPC. I am using Acegi with GWT-SL on the server and it looks to me like Acegi naturally puts a JSESSIONID into the header and is available in a cookie. Does anyone have suggestions on how to: a) server->client do something like generateSessionIDAndSendItBackToClient() but still use Acegi, and b) client-> pick out the JSESSIONID from the GWT-RPC payload and use it in Acegi's filters to check whether that JSESSIONID has a valid signed in user associated with it?

Comment by k.ramins, Jun 29, 2008

I copied and pasted "BCrypt.java" inside "client/util". When I try to hash the password using this utility class, I am getting this error and app is not loading.

ERROR? Line 19: The import java.security cannot be resolved

Do I need to configure anything in "<module>.gwt.xml"?

Comment by Schimki86, Jul 23 (2 days ago)

I have the same problem like k.ramins...

BCrypt.java lies within "client/helpers".

ERROR? Line 18: The import java.security cannot be resolved

Can anyone help?


Sign in to add a comment