4

I am building a web application where the front-end is a single-page-app and the back-end serves it through a RESTful API. I want to make sure I implement user authentication with the best security practices.

I am planning a system that will perform the following steps to ensure authentication security:

Signing up (or changing password):

  1. User sends username and password to server in plaintext via HTTPS
  2. Unique salt is generated with Python's urandom function (32 chars)
  3. Salt prepended to password
  4. Salt + password is hashed with bcrypt
  5. Salt and hash stored in database table (SQL database, slower than key-value but I'm not too concerned about superspeed for logging in)
  6. Random session id generated with urandom (32 chars)
  7. Session id stored in key-value db (Redis? Key: session id, value: user id) and sent to client along with user object (obviously without salt and hash)

Logging in:

  1. When logging in, user sends username and password to server in plaintext via HTTPS
  2. Server retrieves salt and hash from users entry in SQL db
  3. Salt prepended to password and put through bcrypt
  4. If both hashes match, session id generated with urandom and entered into key-value db
  5. Session id sent to client with user object

Any other request to the server:

  1. Request and data sent via HTTPS including user id and session id
  2. Key-value db searched with user id, if session ids matching, return requested data along with user object
  3. If not matching, return error 401

Session handling:

  1. Allow more than one session for the same user
  2. Set expiration of session to 24 hours, when accessed, put back to 24 hours
  3. Allow persistent session which expires in 1 month, when accessed also put back to full expiration time
  4. On logout, remove session from Redis

Will this be a secure, scaleable and fast (when necessary) system? If not, where are the security flaws? What could I do to improve this process? Is this vulnerable to CSRF attacks? Does it improve security to add the client's IP address and USER_AGENT to the session or is this overkill?

Tom Grant
  • 271
  • 1
  • 8

1 Answers1

0

Authentication is a complex mechanism with a lot of potential security failures that should be addressed.

TLDR: use Open ID for authentication instead of implementing your own mechanism.

  1. Brute Force: you must take care of protecting against brute force in authentication (limit number of wrong attempts to login) and also protect against brute force of your session ID. If I were an attacker I just brute force the pair of ID and session ID until I do not get 401... now I have a valid session. You must block that after too. You can use an HMAC to sign the session ID. That way an attacker cannot guess your secret key used to HMAC the session ID and cannot brute force it.
  2. Session ID theft. You did not state how Session ID is sent back to the user. I assume you meant to send it for client side script to handle and send with each subsequent request. That makes your Session ID susceptible for theft from client side script (caused by XSS for example), the way to protect against this is sending it in a cookie with the "http only" flag set so scripts cannot access it (and you need to make sure also "secure" flag set and limit to your domain etc... )
  3. Your mechanism does not allow the user the "remember me" method, hence user will have to re authenticate every time he opens the app, keeping the session ID in a cookie will solve that as well.
  4. CSRF - if session is kept in a persistent cookie you become vulnerable to CSRF. The way to protect against this is using an anti CSRF token otherwise known as Synchronizer Token Pattern

With all this in mind... my final recommendation for you is using open ID to authenticate your users, keep the hard work of authentication to the big guys and only make sure you are using it right, that will save you allot of headache and time and would probably eventually be more secure.

aviv
  • 1,267
  • 7
  • 8
  • I was planning on using a cookie to store the session data, using double submit cookies with every form. Good point about rate limiting login attempts. What is a safe limit without being too hard on the real user who is trying to remember his password? 10 seems common, but seems too low to me. I feel that even 30 every 24 hours would neutralize any brute force attempts. Also I am thinking I will end a session immediately if it ever is passed with the wrong double submit cookie parameter or the wrong user id – Tom Grant Jan 30 '15 at 20:00
  • regarding brute force attempts [read this thread](http://security.stackexchange.com/questions/4431/is-denying-login-after-incorrect-attempts-ineffective), it has some good points. _But, why not use OpenID instead of having to cope with all the security measures needed for a robust authentication mechanism?_ – aviv Feb 01 '15 at 08:25
  • The reason I don't want to use OpenId is mostly based on my customer base. The average user will not know what it is, and will perhaps be suspicious of seeing a system they are not used to. They will see no benefit to logging in with their Google account or Facebook account or whatever, and it may turn them away. It may give them the feeling that they are always logged in, which can seem insecure to an uninformed user. Since it is not in the normal usage patterns of my customers, it is not useful and is in fact a detriment. – Tom Grant Feb 01 '15 at 17:24