Sunday, December 19, 2010

Browser session management, authentication and breaking with RESTful principals

REST is a series of general guidelines for simple, compact and effect remote procedure calls over some transport (generally HTTP). And the guidelines are very useful limitations that can help shape a cohesive API.

One major tenant of REST is sessionlessness or statelessness of a request. In other words no client state should be stored on the server. Sticking to this approach generally allows for a simpler API and simpler coding exercise in building the backend behavior. This tenant also facilitates load-balancing of requests or robustness (i.e. server failures)--meaning that with no client state on the server it is much easier to distribute requests among server clusters.

So, in my experience I really get the concept of sticking to statelessness in the design of an interface. Every request then that comes into a RESTful system requires authentication. An example of a request could be:

> POST /some/rest/api/my_api_method HTTP/1.1
> User-Agent: curl/7.21.0 (i486-pc-linux-gnu) libcurl/7.21.0 OpenSSL/0.9.8o zlib/ libidn/1.15 libssh2/1.2.6
> Host:
> Accept: */*
> authorization: Basic dnlhdRRh5nZ5YXR0YQ==
> content-length:0

The request above contains no body and the access is allowed with the correct authorization header. As with the example above the authorization header parameter is required to accompany all requests (that need authorization that is). This does simplify code on the backend as this means all requests can be treated identically with request to authorized access.

And this is all fine and dandy. And makes for a nice simple contract between the frontend and backend.

However, this doesn't work well for browser based REST clients (note that a REST client can be any application, including browsers). Let's step back a second and look at how the browser stores stateful data. Such as a username and password accompanies each request as part of the authorization header parameter. On the client this can be kept in the following locations:
  1. In memory via the browser session object
  2. Cookies
  3. URL or form based techniques
The browser session would be preferable as this is essentially in memory (i.e. volatile), and when the browser is shut down or the user leaves the site the memory should be released along with the sensitive username and password. Unfortunately it's a little too volatile. A browser refresh will blow away the session data--which means the user will be prompted for their username/password again. Not something you were expecting I would think.

The cookie approach is elegant and does the job, especially with timing out access, but is considered insecure. If the password is obtained through some browser specific weakness in accessing the cookie, the hacked access is good forever (or until the user changes their password if the hacker hasn't already done that for them).

Or pass the username/password combo back and forth via POSTS/GETS between the server and client. This is an awkward approach though and mixes the authentication behavior into the client/server presentation logic.


The only real way to avoid weak or insecure password storage and avoid the problems mentioned in the techniques above is to keep the password out of the client. The client then needs to exchange a token instead. This token can be created by the server and returned to the client. And now we are now back to session management. In this way, the storage of the token is still considered insecure (if kept in a cookie) for the same reasons given above, but the single key difference is that the token or session key lifespan is now controlled by the server and if obtained maliciously will only provide for access for a short period of time (or server controlled period of time).

And this precisely works against the concept of RESTful principals. The best you can make of it then is to keep the session object as simple as possible and have it extend across all of the API (i.e. reducing state transitions).

1 comment: