Is this user auth secure enough? - php

I am trying to move away from using md5() for storing and comparing passwords. So I want to start using password_hash().
Now, how I used to do it, was I would store the username and an md5 of their password in their session or cookies (if they chose "remember me"), and then check the database to see if any user existed with that username and md5'd password. I realize this is not very secure, which is why I want to stop this.
I can no longer do this because password_hash() always changes, so I cannot store a hash in their session and then check for it in the database, because I need to use password_verify on the unhashed password.
So my question is, if I store a hashed "session id" and "token" in the user table when a user successfully logs in, and then store that in the persons session/cookies along with the user id in order to check the database with, is this secure enough? When I say hashed "session id" and "token" I mean sha256'd or even md5'd hash of random large numbers...
Example:
User logs in -> hashed "session id" and "token" is store in the users cookies/session, and their row in the database is updated with the hashed "session id" and "token".
User visits site -> code checks to see if their "session id" and "token" exists in the database based on their browser session/cookie vars. If it does, it assumes that the row found represents the current user.
Any insight would be greatly appreciated.

What I'd do is when the user logs in, generate a unique id for his login using uinqid() (http://php.net/uniqid) and then store this in a new table. Id then check this table to see if the cookie matches the uniqid stored in the table.
You'd have to make sure the table row is deleted when the user logs in again, but this would cause a problem if the user sets a remember me on multiple devices, so I'd set an expire date in the table for each id, and the login script would:
SELECT * FROM 'UNIQIDS' WHERE $current_date_and_time > 'EXPIRE' and delete all results
Check for the existence of a cookie. If there is one and it matches the uniqid, create a session on the computer, else show login page
Upon user login:
Check if there is already a uniqid stored in the table
If there is one stored, if the current date and time is past its expire date, delete the row
If the one has expired generate a new one with a new expiry date matching the expiry date of the cookie you are generating. If the one hasn't expired, calculate the time between now and the time it expires and create a cookie containing its value and expiring in the time you calculated.
This is highly secure as it would be hard to fake this cookie, and it doesn't ever pass the users password information to the client machine.
For even more security, you can md5 the uniqid you generate but theres no real need, as it contains no important information.
This is rather complicated but if you take it one step at a time, it shouldnt be impossible.
Good luck!

For best password hashes and usage and yet simple to code is below example...
$salts= ['cost' => 12];
password_hash("Password", PASSWORD_BCRYPT, $options);
$salts is an array which combines miltiple times when password_hash() is used.
PASSWORD_BCRYPT is an algo which hashes the string with "$2y$" identifier and with blowfish encryption algo. This outputs 60 char of jumbled set.

Related

What's a secure way to create a "remember me" system in PHP with cookies?

I'm at the beginning of a project that will have a "remember me" option when the user authenticates.
My user's database table have the following basic structure for authentication:
id : a random number generated when user is registered. (key)
username : an username choosen by the user, can be changed to another unique username.
hash : the hash of the password created with "phpass" when the password is set.
I'd like to know a safe way to keep the user logged in, even in more than one computer, using cookies and MySQL.
I wish I can use the same cookies to store a temporaly session or a "remember me" section. I've read about tokens and about hashing all user information to a cookie but is it safe? I checked Facebook's cookies that are used after user authentication and there's user id entry, is it really necessary for what I whant to do?
If I decide to hash information to the cookie should I use "phpass" that probably is slower or a simple MD5 function, seen that the authentication verification wiil be in every page and every AJAX request? Should I renew a user token every time I verify for login?
Finally, what's the best choice I have? I know there's a lot of questions similar to this but I didn't found something like "the best way" to do this. In every post I find there's something different and contradictory about this subject. I'd like to know a safe and clean way to do it.
I would recommend using a separate table to store saved login sessions. This table will store a unique hash generated at the time of user choosing to "remember me", the user's IP address, and their user_id.
When or If a user decides to keep a persistent login, you will generate the hash, save that hash as a cookie value, and store their IP / user_id in the "remembered" table.
In your session_start/check sequence, first check if session is set -- if not, check if cookie is set - if cookie is set, match their IP address to the cookie's hash value against the database and then if all checks out, set their session status as "authenticated".
The reason for having a table using their IP address and a unique hash is to allow multiple devices/computers to be persistent. Each device would have an entry in your remembered_sessions table.
This method does not store any passwords in a cookie, and only those who have successfully entered their password will have this cookie on their computer. Additionally even if someone grabbed that user's hash in their cookie they would need to be on the same network to be considered authenticated.

Bcrypt 'remember me' cookie value

I'm using Bcrypt as shown in https://stackoverflow.com/a/6337021/999516 to store passwords in the database and i'm trying to add the 'remember me' feature to keep users logged with cookies.
When a user logs in succesfully, i re-create the hash and update it in the DB. If the user has checked the remember option, i create a cookie with USER_ID, expiration and now i don't understand: which value must i store in the cookie? the complete char(60) hash?
I would recommend implementing a separate "remembrance" hash to store in the cookie, with a corresponding DB table associating that hash to a specific user ID and expiry. Storing the actual user ID in the cookie is a Really Bad Idea since you have no way of verifying that they didn't just change the user ID stored in the cookie. By storing a completely separate hash in the cookie, you can easily lookup which user it belongs to in your DB table and auto-log them back in if it's valid and unmodified.

php user autologin

Can't find answer to my question.
I'm creating registration and need autologin for user with cookie.
What kind of information should be stored in cookie? Is it username + hash password or what
First, just to echo what everyone else has said, this isn't so much an auto-login feature as it is a 'remember me if I navigate away from the page' feature.
How I have seen it done in the past is similar to the implementation explained by frostymarvelous. Basically I have seen 3 cookies used:
Cookie 1:
name - 'username'
value - user's name
Cookie 2:
name - 'salt'
value - random salt created for this particular login
Cookie 3:
name - 'authentication_hash'
value - Hash of a couple unique pieces of data that only your website can duplicate. If you can duplicate this value in the cookie, then make sure the user doesn't have to login again.
Basically, cookie 3 is the most important cookie and I would include a couple things in this to prevent it from being duplicated easily:
<?php
function isAuthenticationCookieValid() {
// $websitePassword would be a unique string stored in a file that is only
// accessible by the server running your website.
include("websitePassword.php");
// $hashOfUserPassword should be a hash of the user's password and should be
// retrieved from the database in hashed form because that is how you should
// store passwords.
$hashOfUserPassword = retrieveUserPasswordFromDatabase($_COOKIE['username']);
// $salt should just be read from cookie.
$salt = $_COOKIE['salt'];
$authenticationValue = sha1($websitePassword . $salt . $hashOfUserPassword);
// Compare authentication value in cookie with calculated authentication value.
return $authenticationValue == $_COOKIE['authentication_hash'];
}
?>
The contents of 'websitePassword.php' should just be:
<?php
$websitePassword = "secretWebsitePassword"; // Obviously use a better password
?>
I would also suggest making the cookies expire after a timelimit to make your website more secure and you could possibly add a time element to your hash so if they try to use that particular hash after a particular amount of time, they will not be logged in automatically.
I would not store the hash of the password in a cookie because the hashing can be reversed (at least for weaker passwords).
Generate a session token which you can store in your database and use in cookies.
See: Session token - how does it work?
What I do is, I hash the useragent, tack the
user ID the end of the string.
When a user is not logged in, I check for the cookie, split the string, verify that the useragent is the same, and then proceed to log the user ID in.
This btw is not too secure, but it is basically the way It is done. This is remember me btw.
For an auto login like xtgem, an url with the username and unique identifier is given to you. This is bookmarked and when the user clicks it, the page makes the checks and logs users in.

PHP login cookies security

In most of past questions on SO about security in 'Remember me' feature in login systems, Persistent Login Cookie Best Practice is suggested.
If I understand correctly, this approach goes like this:
If user checks to remember the password, the cookie consisting the username, followed by a separator character, and some large random number should be set. For example:
$_COOKIE["login"]; ="adam:8794383bb07608636dab808df6c9e29c"
store username and hash string in database.
if both cookies exist, and are mapped to each other in db, the login is accepted.
After authentication, remove the random number from cookie, generate a new number and store in cookie. (Do I need to update this newely generated hashed string in the database as well?)
When user is logged out, current cookie number is also invalidated.(Should I remove username and the random string from the database?)
Is it all?
As in my previous question, I was told that if someone can access the cookie, they can easily authenticate. So how does this approach solves that problem?
Many thanks.
Actually, here is what I would recommend. Sample DB Schema
Users:
user_id
username
autologin_hash
autologin_expire
Process:
User clicks remember me
Server assigns a unique token and stores it in the database and sends it as a cookie.
Server also assigns a fixed expiration date in the autologin_expire field
Check to see if the user's cookie equals the one stored with their account on the server AND it has not expired
All is good...login, delete the hash, regenerate it, and update the expiration date for the next login
You never, ever want to store usernames or passwords in cookies as they are vulnerable to theft if you are not using SSL. Using a unique hash and clearing it on each login solves these problems: 1) it prevents auth details leakage, 2) it makes a auto login valid only once (cookie cannot be stolen and used again), 3) it enforce a hard expiration date server side which helps prevent abuse, 4) and the long unique ID is hard to impossible to guess so hackers would have to actually steal the cookie to gain access.
Edit: If you want even more security, make a note to clear out the hash if the user changes their password. You don't want valid auto login hashes floating around if the user changed their password out of fear their password was revealed.
4). You do need to update the hash, otherwise the person won't be automatically logged in again.
5). You should for clean up, but if it is invalidated, your code should not process it as valid.
As for stopping other people from loggin in with that cookie, you could do...
User agent must be perfect match as well.
Once logged in, their account is marked remembered login. When it comes to changing passwords, making payments, you request their password again.

How to Store Passwords in Databases and Cookies (PHP/MySQL)

Having read this article and many others out there on how to not store passwords in databases and cookies, I'm wondering now how I should do it...
What I've come up so far (after reading around a bit) is taking the clear-text user password, padding it with salt till it fills up 512 bits (64 bytes => 64 chars, since the page is non-unicode), and then doing
$pwhash = hash('sha512', $saltedpw);
for ($i=0; $i<1000; $i++)
$pwhash = hash('sha512', $pwhash);
Then I would store (UserName, HashedPw, Salt) in the database, but what do I do about the cookie (to identify users that want to stay loogend-on after the session has expired)?
First, calling hash 1000 times does not help anything, once is enough.
For remembering the user login in cookie you have two options:
As has been said, you can generate a random token and store it in the database along with the user information. When a user with no session cookie enters the site, you check if there is a cookie with the token and do a DB lookup. If you found a user with such a token, log them in. You might want to do some additional checks, like whether the current IP is the same as the IP when they first logged in.
You can store the user ID in the cookie, but then you have to sign the data using a secret key to make sure the user can't just modify it. HMAC-SHA-1 is a good way to do that. The advantage is that you don't have to store any additional data in the database. You only have to verify the signature and do a lookup on the user ID. The disadvantage is that you have to make sure the signature code is secure (HMAC-SHA-1 with a longer secret key should do that).
You do not have to store the password of the user in the cookie. You can generate a long random string (similar to a sessionid) that you store in the database and in the cookie. You can change that string everytime the session expires and the user comes back. When a user accesses the site you can check the cookie value against the database and see who the user is.
In the database store only password hashcode, and cookie should contain session id, often called SID. In another table store all SID (with userID) and thats all.
But don't forget that PHP has build in very simple and usefull session api, use it better :)

Categories