Ok, first I was a bit confused when reading
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.
at https://code.google.com/p/google-web-toolkit-incubator/wiki/LoginSecurityFAQ because I didn't understand the nature of XSRF completely and thought: why does it matter how the id gets transmitted?
Then I read http://www.gwtproject.org/doc/latest/DevGuideSecurityRpcXsrf.html and now I understand that XSRF works despite NOT knowing the cookie content (your browser just attaches it to the request, so you exploit your browser's knowledge of the cookie's content - although the browser does not tell 'YOU' or the attacker about the content. The cookie content itself remains uncompromised by that attack). So any proof of knowing the cookie's content validates that the request is not part of XSRF.
I don't like the solution as implemented by GWT (http://www.gwtproject.org/doc/latest/DevGuideSecurityRpcXsrf.html) because it needs a separate call to the server. Please tell me if my ansatz is secure and if I understand the XSRF stuff correctly:
To prevent XSRF, I just copy the session ID contained within the cookie into some non-standard HTTP header field, ie. "X-MY-GWT-SESSION-ID: $sessionId", when doing RPC calls.
That way, I do not need to make any additional calls during app startup because session validation is already done during delivery of the gwt app by destroying the cookie if the session is not valid any more (see How can delete information from cookies?).
So here is the complete security implementation:
- registration: client submits cleartext credentials via RPC call to the server, which in turn stores the password using a hash during registration in the server's database (How can I hash a password in Java?)
- login: client sends cleartext pwd via https+RPC, check password on server, if ok: store and return (via https) random UUID. That UUID is the shared secret stored on server and client that is used to identify the authenticated user over possibly many browser sessions to avoid requiring the user to log in each time he visits the site.
- server sets cookie expiry time to 0 if session is not valid any more so that the client clears the session id and the GWT app detects that it needs to re-authenticate.
- on server side only accept session UUIDs sent through a special HTTP header field to prevent XSRF
- handle invalidated sessions on client side (either no session cookie or RPC request produced auth failure)
- to prevent re-authentication shortly after gwt app loading, the server side devlivery mechanism (ie. index.jsp) deletes the cookie some time before the timeout actually happens - delivering a page and asking for authentication a few seconds later is a bit dumb.
Example sources for the GWT part can be found there: https://stackoverflow.com/a/6319911/1050755. The solution bsaically uses GWT XSRF classes, but embeds the MD5-hashed session ID directly into the web page instead of getting the token via a separate RPC call. The client actually never calls any cookie-related code and the server has only embedded a request.getSession().getId()
call into the jsp page.
Any comments, suggestions, critique? Do I miss something important?