When you’re dealing with users in a web environment, invariably you’ll want to know who’s who. Because HTTP is stateless, web applications expect some random and difficult-to-guess piece of data with each request that’s unique for each user. In most modern web frameworks, this data is stored by the browser as a cookie. This correlates all requests from the same browser with a server-side session, which can be used to stash data relevant to only that user. Let’s call these session mechanisms: server-side caches that are mapped through a session identifier. Authentication is handled by checking if the session identifier in the request has been used previously to submit a valid username/password. There is another approach – persistent authentication – which doesn’t use a server side cache. Instead of a session identifier, it expects an authentication token. This authentication token is parsed and validated for each request. The value, while it may be difficult to guess, is not random – it’s based on the user’s identity.
Think of HTTP basic authentication as a canonical example of persistent authentication. The authentication token is a username and password which are Base64 encoded and sent in a request header. This is basically like sending a password with each request – an attacker can simply replay a captured value, forever.
There are a host of homegrown web applications that pass some form of credentials in each request, rather than a temporary, random session identifier. The tell-tale sign is a cookie or hidden field that is the same for each user each time they log in. I’ve seen this design flaw a few times recently, and it’s difficult to patch because it gets so baked into the application code. Here are some of the potential problems with a persistent authentication mechanism:
1) You can’t implement server-side logouts effectively, because the token will always be valid.
2) You can’t implement server-side session timeouts. Once the persistent authentication token is known, it’s good forever.
3) You can’t lockout brute force attacks against the persistent authentication token.
4) If someone can reverse-engineer the method for creating an authentication token, you are hosed.
These flaws are a package deal and there’s no good way to fix them without changing the entire authentication design. That being said, persistent authentication mechanisms can be more resilient in some cases:
1) Session fixation attacks are less likely because the token is only available to authenticated users.
2) Cross-site request forgery attacks can be made more difficult in some cases. See how the Twitter API uses HTTP basic authentication and prevents CSRF attacks.
Forms authentication in ASP.NET uses a forms authentication ticket – it’s a signed and encrypted username, with some extra things thrown in. Forms authentication tickets are not exactly persistent because they time out, but they suffer from one of the same issues – you can’t easily invalidate a forms authentication ticket at the server. You can only clear the client-side cookie. Either you have to wait for it to expire or keep a record of invalid tokens. This was described in a Foundstone whitepaper.
Neither architectural mechanism is perfectly designed. However, session mechanisms tend to be more commonly built into frameworks, and thus more vetted, so any sign of persistent authentication should raise a red flag.