I've been told that it is insecure to store things such as passwords, usernames, and user ID's in cookies, and that instead you should store a sessionID in a cookie. Here's where I get lost.
My objective is to have a basic 'remember me' feature. Normally I would store user login information in a cookie, but as this is unsafe, I'm wondering what the alternative is. I understand that each time I create a session it creates a cookie which creates a unique ID, but expires when I close my browser. So how do I get access to this session information after the browser has closed?
All help is appreciated.
Possibly the best approach, as has been suggested and what most third-party apps do, is to create a "user_sessions" database table with the following fields:
session_id (var_char)
user_id (int)
ip_address (var_char)
last_logged_in (unix timestamp)
Then use a cookie to store an md5 hash of whatever you like, possibly:
md5($username.$ip); //since md5 has a lot of reverse look ups now you should use a number of fields to validate. You could use a different crypto function to make it more difficult to crack, but md5 is the simplest version available in all php versions.
EDIT: You will then compare the stored hash from the cookie with the database session_id to see if they have already logged in. The reason to combine a couple of fields in the md5 function is to create a less "guessable" hashing format. It makes it less likely someone will be able to edit a cookie and login as someone else.
This could be done for all users (this way you can track who is online) and just set a "persistant" login variable in the cookie. eg.
p_login=true || p_login=false
That way you'll know whether to auto login or force login.
note: You may be able to look at http://www.openwall.com/articles/PHP-Users-Passwords for a different way to hash passwords, session_ids and users.
This could be a fairly steep learning curve. Have you considered using a pre-existing CMS or other solution for what you're wanting to achieve, or even a framework that might include this functionality?
For a 'remember me' feature you can send out cookies containing the user ID and a hash of that user's hashed password hashed again with some known, but secret, token. That solution doesn't allow you to remotely expire someone's login, however, without resetting someone's password.
Another approach therefore is to generate a unique token for that person's login and have another database table relating that unique token to a particular user and expiry date.
Related
I use cookie to store user credentials. I have two questions:
1- Is hashing cookies necessary? Using for example md5
2- Should I store passwords with usernames or storing username is enough to authenticate the user?
Cookies can be edited by the user, as a penetration tested, I would say storing any user specific data used for authentication is a bad idea.
The best way to store this is in sessions, that way it is server side and the data is only in the scope of that user/connection.
Don't store credentials in cookies or sessions or anywhere other than as hashes in a database.
What you're supposed to use is a session id cookie. PHP creates one automatically when you call session_start. The session will contain all the data pertaining to identification of the user, like the user-id (you probably just need the user-id, nothing more).
Sessions are stored on the server, so they're tamper-safe.
Cookies are stored by the client so they're wholly unreliable. Use cookies for preference things like language selection or "yes I've seen your popup ad".
salt + md5 is not strong enough to store passwords. Use the built in PHP functions that deal specifically with passwords. See http://php.net/manual/en/function.password-hash.php for more info.
I've read that storing login information in cookies is a security risk since they can easily be edited by the user. My question is if all I store is the username and password in the cookies then why is it risky? If I just made a simple authentication script to make sure the password and the username match up before retrieving information from the database why would this be risky? The user editing the cookies would still need to know the correct username and password that match together to gain access.
I am planning on doing this so users can stay logged in after the session ends.
Well if you store the username and password in the cookies, then they will be accessible to anyone with access to the computer.
This wouldn't be very secure.
No. Do not do this. This is pretty much the worst way to go about it.
A better solution is to:
Have the user log in.
Generate a random token, ie: $token = md5( time() . rand() . $username );
Store the token in the cookie, as well as in the database alongside the user's ID, and the IP address used for the login.
Start a session.
This way when the session expires you can still check the token in the cookie, compare it to what's stored in the database along with the IP address, and then process a non-interactive login for the user.
By doing it this way you're:
Not storing the user's credentials anywhere outside of the server.
Providing baseline protection against cookie hijacking.
You should also store a timestamp along with the token, and expire it after a reasonable period like 30 or 60 days so that users don't have themselves permanently logged into machines they may not want to be logged in on. As well, an option for a user to view and invalidate all of their login tokens so they can be responsible for their own account security.
re: #Gumbo's comment:
I think you're a bit fuzzy on what rand() does. Even if you know the user's name and the exact second that they logged in [via the server's clock] that still leaves you 2 billion possible values for rand(). [on my system] If you want to start just guessing MD5 hashes that's 2^128 possibilities, and it's all moot if you're not on the same IP address that's stored in the DB alongside the token.
The items were chosen off the top of my head for the following reasons:
$username: so the token should be unique per user.
time(): so the token is unique per second
rand(): so the token is reasonably random
md5(): because I felt like it. MD5's hexadecimal strings are easy to use in code, and in this context reversability is a moot point. We are only interested in making the guessing of tokens difficult.
Use mt_rand() and sha512 or bcrypt or I-don't-care-what, but the fact remains that it's not necessary in this context.
I'm setting up a user account system on my web site. The SO consensus seem to be reflected in this SO question/article. It recommends this approach by Charles Miller to store the username and a large random number 1) in a cookie and 2) in a separate table in the DB. The user can be reauthenticated in each subsequent session by querying this table using the cookie (if it exists). If a match is found, then a new $_SESSION is set for that session. It supports simultaneous logins from different computers.
My question...
Prior to reading security questions on SO, I was thinking about storing user information in a way similar to the way vBulletin does it. As I understand it, they store the user id and the hashed password in separate cookies on the user's browser.
After the user logs in, they use a $_SESSION variable (e.g. something like $_SESSION['user_hash']) to maintain the authentication for each page request. I don't have access to vBulletin software, but I assume that $_SESSION['user_hash'] is maintained in a separate MySQL table along with another piece of identifying information - e.g. user id/password hash/other - in order to enable logins from different computers.
I was thinking about creating the hash by doing this:
$_SESSION['user_hash'] = $random_hash = sha1(uniqid(rand(), true));
For future sessions, if $_SESSION['user_hash'] does not exist, then those two cookies can be used to auto-login this person for a new session. I would plan on implementing the $_SESSION security measures outlined in this SO question .
Is the vBulletin approach acceptable from a security standpoint? If storing the user id and the hashed password in a cookie is problematic, would encrypting them alleviate some security concerns? Or could something else be done to secure the cookies?
Thanks for any suggestions.
The problem with this approach is that there is far more potential for session hijacking than with a standard session cookie. If I were to steal that cookie, I would potentially be able to access the user's account for as long as they don't change their password. If session authentication uses a session ID that's unique to the session, it's easy enough to set the sessions to time out after a period of inactivity by storing the last activity time in the database.
Another thing is that I would argue you are overcomplicating your own code. You're already using PHP's sessions, which I've always found to work very well, so why not just store the PHP session ID and a link to the user record in the database in your user sessions table? What more do you gain from setting another cookie with your own hash in it? That's why PHP is such a nice language to use because a lot of these high level functions, such has session handling, are already done for you
I'm creating a login system in PHP, and I want to know how to best protect the user information string in my cookie. I was thinking of encrypting the string with a key somehow? Is this the best way? I'm kinda new to this.
Thanks in advance.
Don't store sensitive information in cookies. Store a session ID hash to connect the logged in user with their account.
Aaron Harun has the right answer for you. There's basically no need to encrypt such data as long as you store it in a session, because that data never reaches the client/browser/user, as it is all server-side. When you create a session on PHP, it handles the cookie stuff for you, so you don't have to worry about that. In most cases, there is no need to deal with cookies. In security, dealing with cookies is detrimental.
I've seen some sloppy sites that actually store the username in a hidden field on a form, which allows anybody to simply edit their local copy of that form and take actions as whichever user they like. This seems like an obvious problem, but cookies are no better.
If you truly think it's a good idea to design a homebrew authentication system, you need to design the database first. Don't store plaintext passwords, store a hash instead (like md5, sha-1, etc) and at that point there's no harm in generating a salt for each password (a random string that you append to the user's password before hashing it, and store that salt with the password hash because you'll need it later--this prevents dictionary hash attacks, ie rainbow tables).
You should never store secure information in a cookie. Cookies are saved in textformat on the user computer, and there are many reason why you should never stock sensitive informations in them :
Cookies are basically text files, which can be opened by anyone on the computer, with any text editor.
The cookies are stored on the user computer, this mean he have no time limit, no connection limit, no processing limit, so he can try to brute force any data as much as he want without being worried of getting ip banned/kicked...
You should only stock things like a username to remember or a session id.
If you absolutely MUST store information in a cookie instead of the user's session, consider signing it with HMAC. The hash_hmac function is a builtin in modern PHP versions.
If you're storing a user login for a "remember me" feature, store both the user's ID and a hash of information that is only available in your database. For example, hashing together the login name and password and storing that with the user's ID in the cookie is reasonably secure. If the user ever changes their password, all the machines he's logged in to with that method would be invalidated, and there's no way to simply change the ID in the cookie and still get logged in, because the username/password hash won't match.
You get sessions for free! That is data stored server side, automatically handled by PHP/framework-of-your-choice. You just put data into the session, which is associated with a random UID stored in clients' sessions. On the clients' side, this is the session cookie. This ID is automatically generated, you can fine grain the behavior manually.
Data stored client side is never safe, no real encryption available. Sessions you will need anyhow for keep track of logged in users. If you have lots of data, you can use the ID to identify associated data from other datastores (DB, XML etc.)
I have been simply writing 2 cookies, 1 containing the user ID, and the 2nd containing 1/2 the SH1 hash of the password (salted). The way it works is self-evident.
I realized that I wasnt doing this in the most secure way. Whats a better way of doing this? Preferably using a single authentication cookie.
Also, is there a point to using "hard to calculate hashes"? By that I mean, using bcrypt, or hashing each item 10,000 times with whirlpool, to make it a (relatively) slow hash function (200 ms vs less than 1 ms just plain SHA1)? I mean if someone breaches your DB and gets the hashes.... what is there left to protect, since all your data is in the same DB (Unless you have some sort of a de-centralized setup, which I dont).
use Sessions. Store the session id in the cookie, and store the state of the user on the server side (loggedIn, userId, IP).
To clarify what you need to store in the session array:
loggedIn: A boolean variable about whether the user is logged in or not. You reuse the same cookie for multiple sessions, so you remember the users username next time they come to your site, etc.
userId: The uniqe id of the user in the database. Use this to get more information on the user, like username, email etc. This too can be kept in the session array after the user logs out.
IP: To prevent someone from stealing the session id and using it, you store the IP of the user as well. This is optional, as sometimes you want to allow the user to roam (eg, stackoverflow allows me to move about with my laptop without logging me out when the IP changes).
lastPing: The timestamp the user was last seen. This can be used instead of the cookie expiration date. If you also store the lifetime of the session, then you can log the user out due to inactivity. This means that the session id cookie can be stored on the users computer for a very long time.
When the user logs out or is logged out due to inactivity, you simply set loggedIn to false. When the user logs in with the right username and password you set loggedIn to true and update the other fields (userId, IP, lifetime). When the user loads a page, you check the lastPing against the current time and the lifetime, and either update lastPing or logout the user.
The session data can either be stored in the filesystem or in a database. If stored in a database, then userId is either a foreign key to the user record, or all the data can be put in the user record.
Hashing
rehashing a value several times is not a good idea, because you reduce the security. Instead use salt, combining a static salt (name of the page for example) and the username of the user, together with the password. A hash that takes a long time isn't better than a fast hash, a hash that results in a large digest is better than a hash that results in a short digest (due to brute force). Using SHA1 should be good enough for a normal site (IE, not a bank or a secret military organization).
Currently the unique token for identifying a user is their username + 1/2 of the salted password hash. This token is static, meaning it will stay the same on each request until the user changes their password. This means if I want to impersonate a user in the system I only need to capture/intercept the token once. (Unless you're introducing entropy into the token during the creation of the hash stored in the cookie). Since most users rarely change passwords an attacker will have what amounts to a non-expiring token to access a user account.
A better solution is to use PHP's session mechanism and calling session_regenerate_id on every request to constantly update the token. Doing so makes session hijacking nearly impossible especially over an SSL connection with an IP address/range restriction.
Currently I make 0 DB calls (except
during login, or when something
changes) for logged in users. I wanted
it to remain that way... – Yegor 7
mins ago
PHP session data is stored in the filesystem by default so you won't be making additional DB calls by using the built-in session mechanism.
Also, is there a point to using "hard
to calculate hashes"? By that I mean,
using bcrypt, or hashing each item
10,000 times with whirlpool, to make
it a (relatively) slow hash function
(200 ms vs less than 1 ms just plain
SHA1)?
Hashing a string 10,000 times does not make it 10,000 times more secure than hashing it once. Hash once with a good one-way encryption like SHA1 or Whirlpool.
I mean if someone breaches your DB and gets the hashes.... what is there
left to protect, since all your data
is in the same DB (Unless you have
some sort of a de-centralized setup,
which I dont).
Salting password hashes protects them from a rainbow table attacks. Currently, it's very difficult if not impossible to crack salted passwords with a rainbow table.
If you want to implement a "remember me" functionality for your site, storing the userid in a cookie is acceptable.
You shouldn't store the password in the user's cookie. If they want to, they can save this in their browser.
Ask yourself how strict your security requirements are to determine how hard this will be or not. I use Zend_Auth & Zend_Acl to handle authentication/authorization in my php apps. If you are currently using a framework you might search it for recommended best practices. Even if you aren't using a framework you could search other sites/applications to get a feel for it. There is more to it than that though when it comes to using https for login/entire & entire logged in sessions, http only cookies, etc.
There's several ways you can do this. I'm not going to go too in depth as there's loads of literature on the subject.
First of all, it's better to use something like SHA256 to reduce the off-chance of collisions.
You should also use salting, or dual-salting with one variable salt (such as the IP -- to prevent stealing sessions). A cookie string would look like YOURSALT123.123.123.123USERNAMEPASSWORD before being hashed.
Use sessions in conjunction with your own cookies.
Depending on your security requirements, use SSL.
It all depends on how secure you need to be. A community website about lolcats has different security requirements when compared to a banking website.
this is the best way and easiest way
step1
in your login/index page enter this code
<?php if(check if username and password is correct)
{
header('location:home.php');
$_SESSION['logged']=true;
}
else
{
header('location:index.php');
}
?>
step 2 in your page you want to authenticate
<?php
if(isset($_SESSION['logged']))
{
?>
your page content here
<?php }
else
{
header('location:index.php');
?>
step3 in your logoutpage
<?php
session_start();
session_destroy();
header('Location:index.php');
?>
thats all