10

So, I've created an authentication system. Poured over it for any kind of security flaws and tested the crap out of it. I think it's fairly secure, but there is one "different" by-design aspect of it that's not usual of a web authentication system.

Basically, I wanted to make it so that authentication could be done without keeping track of each user's session. This means less load on the database, and trivial to scale and cache. Here are the "secrets" kept by the server:

  • A private-key is kept in the source code of the application
  • A randomly generated salt is kept for each user

To make it sessionless, but making forging cookies not easy, this is the format of my cookies

expires=expiretimestamp
secret=hash(privatekey + otherinfo + username + hashedpassword + expires)
username=username

(with otherinfo being things like IP address, browser info, etc and with hashedpassword=hash(username + salt + password + privatekey)

My understanding is that forging login cookies (not cracking the passwords) requires:

  1. Source code access to the application, or a way to trick it to spit out the private key
  2. Read-only access to the database to get the salt and hashedpassword

Whereas the traditional session method requires:

  1. Write and read access to the database (to inject the session, or trick the web app into doing it for you)
  2. Possibly source code access depending on how it works

Anyway, does this seem overly insecure to anyone? Are there any ways for me to improve on it and make it more secure(while keeping with the stateless/sessionless model)? Are there any existing authentication systems which use this stateless model?

Also, the hashing method can be basically anything, ranging from SHA256 to Blowfish

Earlz
  • 604
  • 2
  • 6
  • 15

3 Answers3

14

Your basic concept is not new: you want to have some state associated with the user, but you do not want to store that state yourself. Instead, you store it on the client (in a cookie). Since you want to protect against alterations of such a state (e.g. a client building a cookie from scratch), you need an integrity check, such as a Message Authentication Code. Your construction with a hash function is a crude MAC. It so happens that it is a weak MAC with the usual hash functions, because of the length extension attack.

If you want a MAC, use a strong one, and that means HMAC. It is standard and widespread.

Of course, storage of the secret key (for MAC computations) is a tricky point. Something embedded in the "source code" of the application exists as a file, which (by nature) the application can read, making it vulnerable to exploits which obtain illegal read access to arbitrary files. It would be better (but harder) to arrange for the MAC key to be obtained dynamically by the application through some local communication protocol (the application contacts a local server, which gives the key only to the application); that way, the key would only exist in the RAM of the application, not as a file readable with the access rights of the application. It would not be absolute protection (if your server gets thoroughly hacked, well, that's it) but it would be stronger in practice.

I see that you include the hashed password in the data which is MACed. This is a bit weird; you already have the MAC as authentication: the MAC proves that the cookie data is genuine, thus there is no need for further authentication.

Blowfish is not a hash function; it is a block cipher (or a type of fish) and, as such, cannot be used for hashing unless it is considerably modified, which would mean homemade cryptography, and that's not a good idea.


If you are offloading state on the client, you might want to offload state which the client himself should not know. This means that you may also need encryption. Combining encryption and MAC securely is not as easy as it seems; there are modes for that. I recommend EAX.


Be warned that not maintaining state makes you inherently weak against replay attacks. That's unavoidable. You can minimize the damage by using short validity ranges (e.g. a cookie expires within 15 minutes).

Thomas Pornin
  • 320,799
  • 57
  • 780
  • 949
  • 4
    +1 for actually analysing the solution (and for HMAC). My guess is the inclusion of the password in the hash is to cause the old tokens to be invalidated when the user does 'change password'. Another way of doing this is to include a password generation number or random ID (maybe the salt) rather than the password itself, which causes the tokens still to be invalidated if the same password is re-used. – bobince Nov 30 '12 at 14:59
  • Well, maybe I meant BCrypt instead of Blowfish. Either way, the hash function that's considered very secure and with an adjustable workload. Thanks for the thorough analysis though. I'll have to research length extension attacks more. Also, good note about the file vulnerability bit. The only time I've ever seen this type of key-fetching used though has been with coprocessors dedicated for signing certificates. Could you give more information about how that could be done securely? – Earlz Nov 30 '12 at 15:24
  • 1
    You might also want to take a look at JWT (JSON Web Tokens) – Rob Evans May 03 '18 at 09:57
2

This proposed system is a session handler used to maintain an authenticated state and your method of building session tokens is insecure.

For example, using SQL Injection you can read most of the secret data from the database. If you are using MySQL SQL Injection can be used to read files using the load_file() function which could be used to read the secret from a config file.

In general you should not reinvent the wheel when building a system. I am sure your platform comes with a secure session handler because just about every web application will need one.

Session ID's should be purely random values and an entropy pool like /dev/urandom is an excellent choice. Just because you are using the platform's session handler doesn't mean its configured properly. I recommend reading the OWASP Session Management Cheat Sheet.

rook
  • 46,916
  • 10
  • 92
  • 181
  • Well, this systems already been built and is used in my low-profile blog. The reason I made it is that the alternative is Windows Forms Authentication which is known for being extremely tedious to implement, inflexible for storing the users and sessions, and for being overly easy to misconfigure to be insecure.. Also, I made my own MVC framework over ASP.Net, which wouldn't really work well with Forms Authentication anyway. – Earlz Nov 29 '12 at 21:21
  • Good point about the MySQL stuff though. My system is database-agnostic by design, so things like this are definitely something to worry about. Wouldn't load_file functionality be disabled by default though? (and who would possibly use it!?) – Earlz Nov 29 '12 at 21:22
  • 1
    Also, wouldn't it be arguable that if you find a SQL injection flaw, then write access to the database is almost a sure thing anyway? (making sessions not fair any better) – Earlz Nov 29 '12 at 21:24
  • 1
    @Earlz Why would it be disabled by "default"? That is an unsafe assumption. Also it sounds like you prefer reinventing the wheel, which is looked down upon by the software engineering field. Most databases do not allow query stacking, so you can't just insert arbitrary records. This is really only allowed by MS-SQL and SQLite. – rook Nov 29 '12 at 21:24
  • I'd like real suggestions rather than "you're reinventing the wheel". If some people hadn't "reinvented the wheel", we'd still be stuck with all the programming languages and algorithms of the 60s – Earlz Nov 29 '12 at 22:29
  • 2
    "with otherinfo being things like IP address, browser info, etc" - that sounds like if you have the same public IP as an identified user, you only need to sniff the cookie to assume their identity. Since a session id is just a cookie anyway - why create a new way to store a session cookie. – AD7six Nov 29 '12 at 23:19
  • 4
    @Earlz Except that's only true in cases where the reinvention provides quantifiable benefit. In this case you're reinventing session handling on a platform that already has a working, well-tested, strong, in-built session handler. In fact, your solution is inferior to the default, which is a bad thing. Security is hard - don't try to do it yourself if someone already produced an ideal solution, especially just because you think implementation of their system is hard. In fact, attempting to roll your own when you struggle with the existing implementation is a sign you shouldn't be touching it. – Polynomial Nov 29 '12 at 23:37
  • @Earlz I understand that it's fun to build your own stuff, but it's not the right thing to do here. The reason you're being met with such negativity is that most of us have spent a long time either building things using existing secure implementations of various protocols, or testing other people's not-so-secure implementations of those protocols. We've heard the horror stories. We've seen the gaping security holes. We've spent countless hours convincing management to embrace proper security. Seeing someone attempt to build their own less-secure implementation hits a raw nerve for most of us. – Polynomial Nov 29 '12 at 23:42
  • @Polynomial well, this isn't my first self-made authentication (and yes, the first one was stupid and insecure). And I've tried using Forms Authentication. It requires a ton of extra work and generally sucks. You have to muck around with cookies(hint: easy to get wrong), HTTP basic authentication is difficult, BCrypt support is basically impossible, etc etc. I could go on and on. I didn't just create this because I didn't feel like following ASP.Net's implementation. I created it because their are shortcomings I wished to overcome – Earlz Nov 30 '12 at 01:56
  • 3
    I think it's stupid that this place hasn't escaped the "never implement your own authentication" mindset. Yes, it's not a good idea usually because it's hard to get right. If a researcher came here to solicit advice for a crypto algorithm he's been working on would you tell him "no use AES256 because it's proven". I came here for expert advice, not to be told I don't know what I'm doing. – Earlz Nov 30 '12 at 02:14
  • @Earlz well i think you where told how to build a secure session handler, and why your session handler is undesirable. – rook Nov 30 '12 at 05:12
  • 2
    @Earlz You aren't getting a pat on the back and now you're all upset. You don't have to take advice, and furthermore, nobody said "you don't know what you're doing." All they're saying is that your method is no more secure than the already proven methods. You said "If some people hadn't 'reinvented the wheel', we'd still be stuck with all the programming languages and algorithms of the 60s." They didn't reinvent the wheel, they improved it, or else they wouldn't have been adopted. The consensus is that nobody sees improvement in your method over what's already available, take it or leave it. – Purge Nov 30 '12 at 05:13
  • Can anyone suggest a proven .NET authentication module, then, that has the property of being session-stateless? – bobince Nov 30 '12 at 09:09
  • @Earlz From your reasoning of why you want to do this, I'd say the solution is to use a different platform; if the problem is you don't like how .net works - don't use .net. "HTTP basic authentication is difficult" <- that's a bit of a red flag - http basic auth is just that - basic (it's easy to the point of trivial to implement ordinarily, not sure what complexities .net adds to that; it's also insecure to the point of useless over http://.. though) – AD7six Nov 30 '12 at 09:09
  • @AD7six so if I don't like ASP.Net's built in authentication, I should choose another platform. That seems logical. – Earlz Nov 30 '12 at 15:17
  • @bobince Windows Identity Foundation uses claims identity and doesn't require traditional state management. – makerofthings7 Dec 01 '12 at 03:57
  • @Earlz WIF / Windows Identity Foundation is a module that plugs into the standard ASP.NET or MVC authorization frameworks (or you can implement it yourself). Highly recommended and can be run without managing state on the server – makerofthings7 Dec 01 '12 at 03:58
2

To make it sessionless, but making forging cookies not easy, this is the format of my cookies

What you describe is not sessionless - it's just that the authentication state is held on the browser rather than the server.

Even for an SSL only site it's a good idea to try to detect session hijacking and fixation (for fixation the type of exploits available are more restricted since presumably authentication is directly tied to session management) which means storing data server side.

Authentication is not very useful without authorization (please don't tell me your authorization is built directly into your code) which again depends on information held server side.

You still need to regenerate the hash to verify every request or store the hash in a lookup table - which means retrieving data on the server.

Then if you've got any sort of data processing, then in addition to the transactonal data, you should have CSRF prevention - which is usually implemented by storing data serverside.

I don't see how you've reduced the workload compared with using a conventional web session. If you had simply included the username, the expires time and a hash of the username and expiry time, then yes, could rely on the cookie value as providing equivalent evidence of identity as a conventional web session - but this only allows for a very limited authorization/access model.

symcbean
  • 18,278
  • 39
  • 73