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']
Related
I'm just wondering, for a PHP session, would it be preferred to store a session variable containing a logged in user's ID or username?
At the moment it stores the username, whereas would ID be safer because to potential "hackers", they may not know which user the ID correlates to?
PHP sessions work by giving an "opaque" cookie to users - that is, the cookie is just a number, and the actual data is stored on your server. When a user sends you the session cookie, PHP looks up the number in a table to retrieve the data you've stored for that user.
This means that it is impossible, without access to your server, for anyone listening over the network to figure out what the session cookie actually means. They would need the table stored on your server. So it really doesn't matter if you store an ID number or a username in the session: if they have enough access to see what's in the session, then they could probably just look up the username based on the ID number anyway.
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.
On my PHP website, users can login and have the possibility to check "Remember me" to set a cookie.
What should I be storing as a SESSION variable? The username, hashed password and user ID, or only the user ID? If I only store the user ID, wouldn't it be possible for someone to edit the SESSION and change the ID?
What about the COOKIE? Should I store only the user ID? As far as I know, cookies can be modified by the end user...
It seems that you don't have a clear vision of sessions and cookies!
No body can change the session contents except your code (beside attacks). So you can store everything (reasonable) like user id or username that you need to access frequently. in cookies you must store some obfuscated information that you can recognize user later when he/she tries to access your page. so based on cookie content you can regenerate users session (ie. re-login user automatically). Just to note that user CAN change cookies content so it must not be something simple like user id for security reason.
I just give you a simple example, it's far from perfect but not so bad! you may need to tailor it to fit your scenario:
here you can create cookie content like this:
$salt = substr (md5($password), 0, 2);
$cookie = base64_encode ("$username:" . md5 ($password, $salt));
setcookie ('my-secret-cookie', $cookie);
and later to re-login user you do:
$cookie = $_COOKIE['my-secret-cookie'];
$content = base64_decode ($cookie);
list($username, $hashed_password) = explode (':', $hash);
// here you need to fetch real password from database based on username. ($password)
if (md5($password, substr(md5($password), 0, 2)) == $hashed_password) {
// you can consider use as logged in
// do whatever you want :)
}
UPDATE:
I wrote this article that covers this concept. Hope it helps.
You should be storing the random session value in the cookie. You definitely should not be storing any information about the user in the cookie itself. You can then check the session id in the cookie on each page load to ensure that (a) the user should have access to that content and (b) that the session ID is valid.
In PHP you can use session_set_cookie_params and session_name to set the parameters of the cookie.
For who may prefer using cookies (So you can access it long time later even if the browser was closed) this is a safe way to store even rough ID in cookies:
Create a new field in users database name it X.
Generate a cookie to keep the user ID.
Generate a safe (say long) RandomString and keep it in another cookie.
Also save that random string in the filed of X.
In members area check if cookies of ID and RandomString match the database information.
Clear column X when user signs out and generate data for X on next login.
To prevent library attack to match that random string, you may also force logout as soon as the check fails or blocking that IP for a certain time.
User cannot edit session variable, these are managed on server.
Session Variable Advantage
1.)Secure
2.)Robust
Session Disadvantage
1.) Short life time, untill session exist ,
session get destroyed
when user close his browser
server restart
session destroyed using session_destroy();
So session is more secure
Cookie on the other hand let you remember user prefrences
If you use combination of both , then its advantage to your code
You can store userid and username in cookie, then verify user identity using its combination.
If its not exits then you can login user and keep info in session as well as update cookie.
This is how I'm building a login system:
Login:
Check username and password supplied by user with the database.
If username and password is correct, store only user ID in session, something like:
$_SESSION['userid']=$userid;
If User has checked the option to stay logged in, then set 2 cookies, 1 with userID and other hashed string.
To check if user is logged in:
Check if Session exists, the user is logged. is it ok?
If session does not exist, check if both cookies, userID and hashed string exist.
If Both cookies exist, validate them.
As the Session is stored in the server, is it secure to store only userID ? Can a user pretend to be other user and store his userID in the session and log in as him?
Thanks.
Yes, this method is very insecure. I can sniff traffic, intercept your cookies, and your system will accept me as an authenticated user. You are making the assumption that if you get a cookie with a userid and the hashed string, then that user is the same person that originally authenticated to create the cookie. That is a poor assumption, because cookies travel in plain text (unless you encrypt them), so as long as I can grab a cookie, I can pretend be whoever sent that cookie, and your system doesn't know any better.
Edit:
If you are going to use unencrypted cookies, why not just store the session_id in a database table? That way, at least someone that gets hold of a cookie won't have a valid username. Create a sessions table, and when someone successfully authenticates add a row with their user_id and the session_id. Each time a page is loaded, check to see if the session_id in the cookie matches a row in the sessions table. If yes, you can assume the associated user_id is the authenticated user. This approach is just as secure as the one you suggested (i.e. not very), but it's less complex and doesn't give away valid usernames.
Yes it's possible and very extended, this kind of attacks are called Session fixation and in your system (as David said) anyone who sniff your traffic, or have access to the user's drive and steal his cookies, may supplant a logged user.
The best protection is, of course, SSL, but if you can't use it in your website there are other things that can prevent (but not fully protect against) this attacks:
Save info about the user in the server-side when he login, good candidates for this are the IP and the user agent, but any other data that don't change in the entire session can be valid.
You can regenerate the session ID in every request, with this if the session ID is leaked the attacker must use it before the real user do any other request, but beware because every time the session ID is regenerated (in PHP at least) the user's session data is rewited, so this can be expensive if you have a lot of users or if you save many data of every user (this means that, if you're saving the session data in a file, the file will be deleted, created, and writed again).
Well, right now I can only think in these two, it's not much but at least you will put an extra complication to the attackers.
One more thing, don't trust the user's cookies, they can be changed by the user (or the attacker) at any time, treat it like any other user input.
PD.: Sorry for my horrible english, I'm truly trying to improve it ^_^
you could add an ip that the user id should belong to (in your database), that adds a little extra security - it might not always be the best solution
Yes it is ok to check if the session exists and also check that the user id is greater than zero.
The 'remember me' function is subject to sniffing as it's not over ssl, however that is how 'remember me' functionality is done.
Assuming this is happening via SSL, my biggest concern is your first step:
Check username and password supplied by user with the database.
You should be hashing passwords, and comparing the hash of the user-supplied password against the previously hashed password stored in your database.
You also don't have to worry about storing only the user ID in the session array; the session is stored server-side and is as secure as the rest of your server.
One potential problem is that everything is being stored in cookies. If someone somehow manages to get their hands on the Session ID, then they've also got the username and hashed string.
Chris Shiflett suggests creating some kind of fingerprint from the User-Agent string, or some other regular header, and storing it in a GET variable.
One way to bump up security is to have everything sent over SSL. Any time any kind of potential information is sent or received (such as the Session ID in a cookie), make it encrypted - not just the login form.
It is mostly correct but I don't agree with the cookie-option. This way if someone gets the two cookies can move them to a different computer and still use them.
The "remain logged in" function should be restricted to that computer. A possible solution is that if the user wishes to remain logged in you set the lifetime of the session to 1 week or so. Also you have to store the user's IP address, User-Agent and possibly X-FORWARDED-FOR header, and check them on every pageload against the stored values.