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.
Related
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.
I have a table and have two column for username and password. I want to store a cookie for remember user's login. So what field should i use? I'm getting confused about storing username in the cookie. Because someone can try to log via rewrite a fake cookie. What should i do?
You should never store their username and password in a cookie. For a good example on how to handle this, see: "Keep Me Logged In" - the best approach
You should store a random, unique session id since users can tamper with cookies. PHP's session feature already does that for you - and you can store any kind of data in there since the data itself is stored on the server and only the session id is stored on the client.
Another option would be using a cryptographic signature to ensure the cookie hasn't been tampered with.
After logined user, I keep user ID inside cookie ($_COOKIE['user_id']) and after this mysql check if isset user_id inside cookie and if user_id is exists in DB:
SELECT * FROM users WEHERE user_id = '$_COOKIE[user_id]'
It works, but cookie value can be changed by every cliend, so client can set cookie user_id to 1 or 2,3,4 and it will be loggined, So they can hack page.
I want to hash or secure somehow my cookie user_id value. I hope you understand me.
Can you give me any suggestions?
Do not do that in a cookie. Save a hash in the cookie and store the corresponding user id in your database. You can't make the cookie secure.
To be more clear:
When the user logs in, store a unique hash for him in the database. This could be something like that: sha512('9a7fd98asf'.time().$username). This is the value you save in the cookie, too. You know the user is logged in, if he has such a token in the database and if it matches the value from the cookie. This actually is how sessions are handled.
Cookies are prone to numerous types of attacks including someone stealing a cookie from one user and presenting it later to impersonate that user. If you were to instead use sessions, you would either have to use session cookies or URL, both of which are problematic from a security point of view.
The best you could possibly do is encrypt the cookie so you can later decrypt it when you read the user_id. This will ensure that a user cannot randomly change their user_id. However, this does not protect against one user using the data from the cookie of another user.
To guard both against reply attacks (either by the same user, or by a different user), in addition to storing the user_id, you would also want to store the expiry time in the cookie. When you get back the cookie, you can decrypt and also get the time that you need. This does mean though that this type of replay attack is possible within that time during which cookie is valid.
For encryption/decryption, you can search and find how to correctly do it using the language you are employing. You will still have to test against corrupted cookies (in which case you can assume user is not authenticated).
You want to use a meaningless token. That's the most secure way, because the token is inherently meaningless and cannot be attacked in itself. Because the token also needs to be stored on the server with associated data, this also gives the server the ultimate control over logins; because the server can revoke active tokens at any time (you cannot revoke a cookie which stores just a self-contained user id).
A standard PHP session is such a meaningless token and works just fine for most cases. Sessions can even be configured to last extremely long, and you can even change the session storage backend to a database or any custom backend you want.
If, for whatever reason, you need something else, you still want the same idea:
generate a completely random, meaningless value
store it in a database, together with what user it belongs to
send the token in a cookie to the client
You could store an additional cookie, named 'user_hash':
$_COOKIE['user_hash']=sha1($user_id . md5($user_pass . $salt1) . $salt2);
Using some constant $salt values.
When using the user_id cookie, first check if user_hash matches the user login information stored in the database.
Since the sha1 is irreversible, the password cannot be derived from it.
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.
How to securely store usernames in database, without adding them directly to cookie value?
Example:
I want to display username of logged user.
If he have closed his browser early the only way to do this is $_COOKIE['cookie name']
where cookie value links with username in database.
So I don' t need to hash username.
Is it right? And if it's right, is it secure?
It is secure. Just do not store the password on the client (browser). Also never send the password to the browser.
You can store the username in the cookie, this is safe as long as you do not save the password there.
You can also save there user id, then it does not give away any of the authentication details while letting you find the correct user.
Use sessions. data stored in $_SESSION is stored on server, not on client.
The below is assuming you are talking about a persistent login feature using cookies. For the purpose of just remembering the user name (but not signing them in automatically), having a username in the cookie (optionally encoded) should be okay though. Regardless, passwords should never be in the cookie.
Cookies should NOT be directly identifying, i.e. user ids / names should not appear in the cookie. Instead, you should assign a sufficiently long enough string with random data to the users in your table and store that in the cookie value. Once used you should update the string and issue another cookie.
For example:
john | ewojroj1234ojqewor
jack | ljqwelkn1k31n23k33
The second column will be placed in the cookie. Later you will query that value against the user table and:
fetch the user data and store inside a session
regenerate the random string
issue another cookie
Password changes and signing out should also cause a change in the user token string.
For further reading, Barry Jaspan wrote a good article on this approach.
The best way to do it is to store only the user_id (the uniquely identifying primary key) of the user table in the $_COOKIE or $_SESSION variable - perhaps in $_COOKIE['user_id'].
Then on each page load, you can use that id to retrieve any user information you wish from the database. For example (Note this is conceptual/psuedo-code only. You would of course sanitize/clean/validate/bind the $_COOKIE or $_SESSION data parameter first):
SELECT * FROM user_table WHERE user_id = $_COOKIE['user_id']