2

To avoid having the user to login every time his session expires, I want to implement a token based authentication system.

My scheme works like this:

  1. Send the user login (send name + password) via $.ajax() to a https URI
  2. Create a token via $token = bin2hex(openssl_random_pseudo_bytes(16));
  3. Save $token, userid and date in a database (only accessible by SSL)
  4. Echo the $token and userid to the client
  5. Save the $token and userid in html localStorage on the client
  6. When doing an $.ajax() from client always send userid and $token as POST
  7. Serverside, match the provided $token and see if it is still valid (date not expired).
  8. If it's alright, continue to deliver the requested material

Can you analyze my scheme?

Many people advise against implementing custom authentication processes, as they are often vulnerable to attacks. This makes me suspect that my approach may also have flaws. Can you reveal these flaws to me?

Clawish
  • 129
  • 3

4 Answers4

8

So there are a few reasons why you don't want to do this, although I do not understand the code you presented as I do not deal with that. You should use a third party library to manage your sessions. There are several reasons...

  1. Code is vetted, tested and improved across a much wider audience when you use a built in or well know authentication scheme.
  2. When and if you leave, someone is not stuck dealing with a custom created authentication mechanism
  3. There are probably vulnerabilities in the code, it may or may not be directly in your code but in a service you call, updating that single service may cause issues through the rest of the code, such as deprecated arguments and variables. This may not make your program less secure but it may break it.
  4. Self support is tough, especially when you do a good job and it is running without issue for a year or two, then bam!! in the middle of another project something breaks and you have to take the time to troubleshoot it from the bottom up.
  5. CYA, if you make a mistake and something bad happens, you are the one people will come back to and ask, why didn't you use this or that scheme that is not vulnerable to some attack and you will have to explain that.

Anyway, I hope that helps

atk
  • 2,156
  • 14
  • 15
Brett Littrell
  • 355
  • 2
  • 10
4

On the face of it, with a MITM I can just get access to your webapp as long as one your users is using my "wifi"

Also, why use something unproven when you can use proven technology (OAuth2 would suffice for your purposes and that has been security-tested)

And you have no checking built for brute-forcing your "token" meaning I can just brute-force as soon as I get a "userid" (probably a number so easily guessable).

Also, this example lacks protection against SQL-injections, meaning I could just give mysql a valid token and login to anyone's account.

Solving all of them (without creating hidden backdoors / etc) is nigh impossible for one man. Just use one of the libraries available from the open source community, one that is tested and verified!

TankorSmash
  • 103
  • 3
LvB
  • 8,336
  • 1
  • 27
  • 43
  • Where does the MITM come from? From my reading of OP this would require breaking HTMLS. The token is a 16 byte(128 bits) random string, brute forcing that in an online attack does not seem feasible. Why do you assume that OP does not use prepared statements or ORM? – Taemyr Jan 06 '15 at 09:04
  • simply because OP did not specify he/she is using them.(assume the worst) and a SSL-striper with SSL<-STRIP->SSL connection (with secure-cookie passthrough) would alow me to read all the "secured" data as plain text. (MITM) and a 16 byte (128 bits) value with no rate limit or throttle or abuse detection can be default be brute forced (I can keep on 'firing' strings till I get one that's correct). – LvB Jan 06 '15 at 12:13
  • Also do not forget, 128 bits is only 16385 possible values with guessing 1 a second I would crack it BF within 4 hours 33 minutes. that is way to soon to be safe (assuming a "date" = 1 day for expire of 1 token, I can brute-force at-least 5 accounts a day). – LvB Jan 06 '15 at 12:21
  • 2
    128 bits is a tad more than 16385. It's about 2^128 which is slightly more than 10^38. – Taemyr Jan 06 '15 at 12:37
  • oops, flipped those around... nvm my calculations than (its early and I'mm to lazy to do them agian... :p) – LvB Jan 06 '15 at 12:57
  • 1 billion guesses per second: http://www.wolframalpha.com/input/?i=2%5E128%2F10%5E9+s – Taemyr Jan 06 '15 at 13:00
4

Not a bad start. Some things to watch for:

  • If login fails, don't reveal whether the user exists
  • Implement some form of brute force protection
  • Provide a change password function; require the previous password
  • Perform password strength checking
  • Sessions usually have both inactivity and absolute timeouts
  • Store passwords securely, e.g. bcrypt
  • Use an anti-CSRF token
  • Let users self-manage sessions

And that's just authentication and session management. There's a whole load of other security considerations: SQL injection, cross-site scripting, use of SSL/TLS, etc.

Most authentication libraries do NOT solve all these problems in the default configuration.

paj28
  • 32,906
  • 8
  • 93
  • 130
  • 1
    Attempting to register a new account with a given username will "reveal whether the user exists", as will attempting to send a message to that username. – Damian Yerrick Jan 05 '15 at 23:08
  • @tepples - There's more discussion of that particular issue on [this question](http://security.stackexchange.com/questions/62661/generic-error-message-for-wrong-password-or-username-is-this-really-helpful/62704#62704) – paj28 Jan 06 '15 at 08:55
2

If you take the standard session-id pattern, and implement it using a persistent cookie rather than the more typical session cookie, you get exactly what you describe, only you get a professional implementation of it done by the browser.

Remember: not only can your algorithm have flaws, but your implementation can have flaws as well. The more you have to implement, the higher your risk. Lawri pointed out that you are now responsible for making sure there are no SQL injection attacks in your system.

If you really want to do this yourself, the proper way to vet the algorithm is to identify how someone can use the information. As you have it written, the only difference between your token and a password is that the token technically expires (server side). Accordingly, you should write your code treating tokens with exactly the same care and attention you would give to storing and transmitting a password.

At an absolute bare-bones minimum, you must implement SSL to protect from Firesheep style sniffing attacks as Lawri mentioned. If you don't, then you probably should not be implementing your own session-id systems when this is generally recognized as a "solved problem."

Cort Ammon
  • 9,216
  • 3
  • 26
  • 26