Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 4 years ago.
I am trying to create a secure login system using cookies. I have read a lot of articles and Stack Overflow questions on how to achieve that, but couldn't find anything usefull. Everyone is suggests different ways of achieving that, but those who seem reasonable and know what they are doing, I cant quite understand for some reason.
Can you please explain me, what is the best way to create a secure login system with cookies.
I have heard, that the best approach is tokens. But some people say, that you should add a token next to the user id in the token table in the database - and so what if a person logs in from different devices? Some say, you should track ip addresses for that - and so what if a person logs in from another ip? Some say, you should create a session and a cookie - but then whats the point of the session (If the cookie authenticates a person)...
I have seen a lot off questions where people asked similar questions, and in the answers, people were trying to explain what is the difference between cookies and sessions. I know all of the differences and all of the theory. I just cant understand the technique to make everything secure.
I just cant clearly understand how that system should logically work, so can you please explain that step by step to me. Thank you.
Since you're looking for the most secure solution (as of today's understanding), I'm professionally obligated to point to this blog post which explains the theory, and Gatekeeper which implements it.
Do's of Secure Login Systems
- Don't roll it yourself, unless you're a security expert, or you have a security expert willing to audit your code afterwards (software security consulting isn't cheap)
- Use bcrypt, scrypt, Argon2, or PBKDF2 to hash your passwords.
- Use PHP's built-in session management system
- Use HTTPS everywhere, with Hypertext Strict Transport Security
- Use a Content-Security-Policy header to upgrade insecure requests
- If you need to implement a "remember me" cookie, follow the guidelines in the above blog post:
- Generate two random tokens: a
selector
and an identifier
- Store the
selector
and identifier
in a HTTP cookie, set to httpOnly=true and secure=true so it's only accessible over HTTPS (and hidden to JavaScript)
- Store the
selector
and a hash (SHA256 is okay here) of the identifier
in the token table
- Authenticate the user, based on the token stored in their cookie, in constant-time.
Don'ts of Secure Login Systems
- Don't store passwords in the database unhashed; this is never a good idea!
- Don't encrypt or plainly encode passwords
- Don't use a weak hash function (MD5, SHA1, etc.)
- Don't use an insecure random number generator (you want to use
random_bytes()
, and if you're using PHP 5, random_compat).
Brief Security Analysis of the Above Advice
- If you're using properly implemented HTTPS, you don't have to worry about attacks like FireSheep.
- If you're using
password_hash()
for password storage, and password_verify()
to authenticate against the stored hash, then you've accomplished defense-in-depth against an attacker dumping your entire database
- For long-term authentication (cookie-based), you've separated the lookup (which is not possible to implement in constant-time, and is a random selector generated by a CSPRNG so you're unlikely to guess it) from the validation.
- A hash of the long-term identifier is stored instead of just the identifier itself, as defense-in-depth against read-only database leaks
- The validation is performed in constant-time, which makes it more robust against side-channel cryptanalysis (translation: nobody can use timing information to tease a valid long-term authentication token out of the database)
All of the the popular attack vectors (interception, hash cracking, defeating a weak random number generator) and some theoretical attack vectors (timing leaks) are, thus, eliminated. A little bit of good security engineering goes a long way.
Keep in mind that even security advice must carry an expiration date, so if you read this answer many years in the future some of it may be rendered obsolete. Don't get complacent, better ways are constantly being discovered.