How to store cookies containing sensitive data securely in PHP? - php

I would like for my users to have the capability of "Keep me logged in" when they log in to my website. At the suggestion of the top answer on this post, "Keep Me Logged In" - the best approach, I decided to hash a combination of the user's salt and password in one cookie and store the user's id (a number) in another cookie. Of course, the hash value will also be stored on a database server-side to be validated when the user returns again. The salt value I used is the same one that I used to hash the password of the user when they first register, so it is static - it doesn't change between sessions. There's a few of problems I see with this approach.
1) Is using the registration salt a good idea if it's static or should I generate a different salt each time for the cookie?
2) If someone were to gain access to the cookies and they copy them to a different computer, and then try accessing the website from that computer, theoretically, it will automatically log them in to that user's account, is this not a security issue?
3) In a scenario where some user with malicious intents were to gain access to the database, a secure website would have salted and hashed passwords making it rather difficult for the hacker to gain access into multiple accounts (if at all). But, by simply playing around with the hash and salt values and creating a cookie that matches the values they've changed on the database, they can effectively get access to any account they want, rendering the whole password-hashing process as useless. Therefore, this cookie approach I'm using now is compromising my entire database and all my users' accounts.
So my question is, how do I store a cookie in PHP with sensitive information such as a hash of the user's password without having to worry about the aforementioned issues? Surely websites like Gmail and Hotmail, who offer this "Keep me logged in" feature follow a more secure approach than what I'm doing now, so how would they do it?

Don't store the password in the cookie, hashed or not. In fact, there's no reason to store anything sensitive in the cookie. All you need to do is map a 128-bit (or larger) random id to a user account in your database, and store that id in the cookie. There is no way somebody is going to guess a valid id by remote brute force, especially if you have lock-outs in place.
If someone were to gain access to the cookies and they copy them to a different computer, and then try accessing the website from that computer, theoretically, it will automatically log them in to that user's account, is this not a security issue?
Yes. That's the downside to the feature. However, if your website detects new IP address (particularly from different countries) and requires a second step (text a code to a mobile device, etc), then you take care of this problem along with the general problem of a stolen password. (This of course doesn't help prevent local network attacks, like an insecure public wifi.)
A more convenient solution is to require the "remember me" cookie to use SSL. That way a hacker would not ever see the cookie in plain text transmission, and a local attack would probably be required. (And if such, the remember me cookie is probably the least of the user's concerns.)
they can effectively get access to any account they want, rendering the whole password-hashing process as useless.
Yes, and no. If you use the technique I described (random id) then they can only access accounts that have a "remember me" cookie. But that said, if they have access to your database, they can brute force any account they want. Even salted passwords are easy to crack locally if the password itself is weak.
Also, you can consider the "remember me" login to be a half-login. Access to purchase something, change an email address, etc, would still require a password to be entered. Doing harmless things like posting on a message board could be done without the password.
Finally, note that a PHP session cookie is nothing more than a temporary "remember me" token! So much of this applies to the concept of session hijacking. The "remember me" token simply adds a bigger window of opportunity.
So in short: don't store anything sensitive in the cookie, require SSL for the cookie, and if possible, implement multi-factor authentication ... especially for admin accounts.

Related

Is using cookies instead of a session for storing username and password wrong?

I've started learning PHP by myself, and in the beginning, I would often choose the simplest way to do a task instead of the best way. Now that I'm developing important websites that need to be 100% secure, I hit this dillema,
I'm using cookies on my main page, to store the login session. Basically, the username and the hashed password is stored in a cookie and is loaded and checked against the database any time the user visits a mustbeloggedin page. For my main page, I'm using md5. Not because I want to, but because I have to. I know that poses a great security risk for the user because a keylog attack can basically freely take his password.
On this new website, I'm gonna use sha256, so that shouldn't be an issue.
Here's my question: what other security issues does storing this kind of data in a cookie and not in a session pose?
Here's mine:
Anyone with physical access to the computer can get the user's hash and store it for later use, by manually setting his cookie.
Any infected computer does the same as the above
Data is loaded, parsed, checked every load (not a security issue but still optimization-wise, it's not very good, but I don't mind that)
Anything else?
Does the domain variable inside the cookie make it secure enough not to be read by any other site?
Edit:: I'm also reading about someone intercepting the data being sent from a client to the server. How are sessions different than this? If I store a session , can't the identifier cookie still be hijacked and used by someone else? Would also adding an ip address to the cookie, then when validating the cookie, also check the IP address and if it's different then print the login form again help?
It seems you are trying to make some improvements, but not enough really.
There should never be a need to store passwords in a cookie, session, array, or anything else.
The password should be in the database and not be taken out to chance further access to it, or manipulation of the data holder in some way.
Otherwise, your highly secured database with hashes and salts on passwords, is only as secure as the framework/scripts and variable or cookie you store the password in (which is less secure than the aforementioned DB setup)!
From your comment:
Your question and statement makes no sense, you're describing a login
page and I'm describing about how the website knows you're logged in.
The cookie has the username and the hashed password, not plain text
password
So you store Bob's password in a cookie, with hash etc.
I steal Bob's password cookie. It's hashed, so safe right?
Ok, so I (James) use it on your site. How does you site know I am James, not Bob? It cannot.
It checks the cookie I stole, and password hash/salt/whatever you do match in your checks (otherwise it wouldn't for Bob either so would be useless).
It thinks I am Bob.
So now you start to check other things, if I have another cookie, perhaps username.
I have already stolen that.
So now your site looks at my cookies, sees a username and password, checks them, and says "welcome Bob, here's your personal/sensitive details, do as you wish...".
Passwords stay in the database!
You could try checking user agent, IP, and a load of other arguably less than useful/sometimes useful things etc, but these are things you can do "as well" as password+has+salt, and at the same time not store passwords in cookies or Sessions.
If your only methods to stop a hacker from using that stolen golden password cookie (hashed or not) is to check user agent, IP, and something else that can easily be faked, then your site is not secure.
Also, anytime the user needs to do something like change their password or email address, or check their whatever sensitive data on your site, you ask them to re-type their password.
Possibly resetting their cookies/hash/hash+salt stored in the DB, but depends on scenario really.
EDIT {
Use a cookie to store the Session reference, and any sensitive data in the Session.
Again, what you should store in the session depends on what data it is, if you run your own server, or shared, etc. Shared hosting can have bad config, opening up other security issues, even extending Session security issues.
(Info is in the links below - as said in comments, reading is your friend ATM - and then some evaluating and considerations of your specific needs)
}
Here is some serious reading for you:
First, your MD5 and even SHA256 are not secure:
http://php.net/manual/en/faq.passwords.php#faq.passwords.fasthash
Hashing algorithms such as MD5, SHA1 and SHA256 are designed to be
very fast and efficient. With modern techniques and computer
equipment, it has become trivial to "brute force" the output of these
algorithms, in order to determine the original input.
Because of how quickly a modern computer can "reverse" these hashing
algorithms, many security professionals strongly suggest against their
use for password hashing.
Also read the link for that quote - the bit about how you should hash, and the bit about salts.
Also, importantly, read about how to correctly store salts and hashes. There is a LOT of BAD advice out there which is misleading to the point you end up with barely any more security than if you just used MD5.
Storing the salt in the DB with the hashed password is fine, just also use unique salts etc (it's all there in the link, about mcrypt/blowfish etc)
A must read, even if you only take bits from it (and even if you ignore the rest of my answer):
The definitive guide to form-based website authentication
Faking Session/Cookies?
More reading:
What is the best way to prevent session hijacking?
Also read about:
Session fixation; Session sidejacking; Cross-site scripting;
And again, given you stated this:
Now that I'm developing important websites that need to be 100% secure
You should really spend a lot of time reading about all these things.
Cookie/session hijacking is real, and generally simple (script kiddie stuff).
If you want to produce secure websites and applications, you really need to learn about quite a few attack methods, preventions, etc.
Best way is read the links I've given, then any "branches" which stem from that read about them too.
Eventually you'll have a larger picture of the vast range of security concerns and resolves to them.
Some takeaways for cookies.
You want to limit any sensitive information saved within as it is not secure.
Cookies are perfect for session ids which you can then use to query your database and check if it is expired, matches an ip, matches user-agent and any other security/validation checks you want to do before you route to relogin or resume session.
http://php.net/manual/en/features.cookies.php
You mentioned user authentication. Most encryption protocols can be broken by using and md5 is considered 'broken' at this point due to completeness of lookup tables with all the hashes and the slight variations between hashes.
How can I make MD5 more secure? Or is it really necessary?
Salting your hash is crucial which adds another layer of security as is additional cdn/server restrictions to block/restrict brute force attacks:
https://crackstation.net/hashing-security.htm
http://www.cs.virginia.edu/~csadmin/gen_support/brute_force.php
If one is overly paranoid you can implement two factor authentication ( expensive? ):
https://isc.sans.edu/forums/diary/Implementing+two+Factor+Authentication+on+the+Cheap/9580/
http://www.twilio.com/docs/howto/two-factor-authentication
Don't store any credentials in cookies. There is session cookie and that is enough. In your database you can create a table where you will store PHP session ID together with user id. It is enough to check user's login and password once, at the logging, to establish a session.
I was doing the same as you do: storing login, password and session id in cookies and had many problems - occasionally for unknown reasons the browser was not deleting one of those cookies, or I had problems with paths of those cookies. I had to develop very complicated methodology for assuring that those cookies are properly set and that all of them are present in a given moment - I tinkered with removing and adding those cookies manually in the browser and had to come up with new ways of preventing the problems arising from such activities, but I was always able to make up new way of breaking that down and had to come up with new mechanism for preventing that.
All of this mess stopped when I finally decided to leave only one cookie - session ID, which I authenticate before every session_start() call - you can check if such a session exists and even compare current browser footprint with previously saved one. It is then very simple to foresee bad scenarios - when somebody deletes this cookie, session is over, garbage collection will clean it up. If somebody changes it or adds fake one - you can compare it against your sessions table and not start a session. To have better control over the sessions, use session_set_save_handler functionality.
There is a lot wrong with your chosen implementation.
the username and the hashed password is stored in a cookie
Don't do that. You should consider the content of cookies insecure.
and is loaded and checked against the database any time the user visits a mustbeloggedin page
There is no need to do that at all, if you know the user is already logged in (session).
I'm using md5
Using md5 at all precludes any semblance of security.
On this new website, I'm gonna use sha256
That will make almost no difference if credentials are still stored in a cookie.
So what should you do?
When a user authenticates themselves store their user info in the session. Any time you need to check if the current visitor has already authenticated check the session data. The session's data is stored on the server - it is secure. There's no need to call the db to find out who the user is on each page load, if the user's data is stored in the session.
Do not use cookies to store user credentials, especially if you're storing the password hash as stored in the db.
Don't use md5 - and if you're "forced" to do so change it at the very first opportunity.

best way to secure sessions (consulting)

Ok, yes, I've read the other Qs regarding this topic, but I have several questions more and some Qs were several years old.
Anyways, I'm building an admin cp for an insurance company that contains sensitive client info. Such as passwords, social security numbers, and drivers #.
First Q:
What's more secure, php sessions or cookies? From my understanding of cookies, you can strict them to http only and SSL. Don't know if you can do the same with php sessions. Seems also that php sessions are just quick cookies. Cookies seem more flexible and just as reliable. FYI, I'm using Cookies with http and SSL only. Is there a good reason to use php sessions in MY case?
Second Q:
My sessions/login work like this:
* Passwords are salted and hashed
* Sessions are 32 random chars long
* Sessions are validated when user enters correct pw and are tied to the user's IP
* When a user logs in, the session id and user's password are stored in 2 separate cookies
If the sessions are validated via user pw and tied to the user's IP, can I just have the session Cookie and remove the pw cookie? since I think it's kinda redundant since you can only get a session id if you enter the correct PW. I rather have the session id expose in a cookie than the pw (though it's still salted and hashed).
Appreciate it if my two Qs can be answered. Additional security advice is welcomed :D
Note: Sessions are tied to IP because it increases security greatly. I rather have my users a bit inconvenienced in having to enter their pw when their IP changes when we have SSNs and Driver License #s in our db. Only 3-5 users will have access to the system too.
Do not ever store the user's password in a cookie, in no form of representation.
Regenerate the session ID often
Use strong hashes (no MD5) like SHA512 (consider also stretching the hash)
Sensitive data should be on the server-sided session store:
Cookies are sent along every request to the cookies domain, hence increasing the chances of being intercepted greatly. Server sided session data is only outputted when needed.
Pass along a session-tied identifier to each sensitive request as an auth token to avoid CSRF
Do not directly bind the session to an IP. Two people using the same AP or private ISP have the same IP and sessions could be mixed up.
SSL is not magical. Don't relay on it too much.
Sessions are stored on server, cookies are stored on the client (browser). Session data that belongs to a user is identified by a cookie (Session ID).
I'd say Sessions are safer (you can also apply some encryption for better security).
Don't store the users password in a cookie. Not a good practice even if it's hashed.
You can store an encrypted serialized array containing necessary info to authenticate the user : ip, user agent, username, user id, but not the password.
You can also make the site (admin CP) work on SSL only. That way data is not visible in plain text on network.
Is the password in cookie salted and hashed? Beware - there is no good answer to this question!
Tying sessions to IPs really doesn't help much - IPs are cheap, easily spoofed etc. I'd go with SSL, cookies/sessions, perhaps even one-time-cookies, consumed and reset on each pageview.
Sessions are stored on a server, either in a database, filesystem, memcache, etc. User is tied to the session by session id, which is stored at client either in a cookie or in a URL. Neither is "very very" secure, since session hijacking is possible by stealing session id. But since you've tied session id to an IP, you've done quite enough.
Now to password stored in a cookie. Do not do this. Never. Even though they're hashes&salted, it's still better that attackers do not see them. You've got another level of security if they're only stored in a database, since in that case, attacker also has to break into db.
It helps if you're regenerating session id using session_regenerate_id() before doing any important action that could compromise the system. Also, take a look at XSS and CSRF attacks and mechanisms to prevent them, like form tokens.

database security

I've been reading about database security when it comes to websites. And it says an attacker could steal a database and then have as much time as he wants to get all the user's passwords.
If an attacker stole the database, why would he need the passwords as the authentication is done in php?
So he could just access all the user's information without knowing the password. Eg a forum with password protected areas.
The attacker could try and get the password of a moderator or user with access to the protected area by getting the database (eg the attacker could be an employee of company that hosts the database), and then go to the forum and log in as the user.
or the attacker could skip that and just look in the table of posts in the hidden area.
Basically if the attacker had access to the database, why bother with username and password when you can access that data without needing to authenticate.
(this blog post made me ask the question: http://www.richardlord.net/blog/php-password-security)
You have an obligation to your users to protect the password as much as possible. That means guarding the database from theft. That also means doing a strong salted hash so that if the attacker does get the database, it'll take a prohibitively long time to extract all of the passwords (it's always possible, but make it not worth their while).
One way is to use a multiple salt hashing system. Basically you use 2 separate salts. One you store with the user that is unique for each user, and one for the entire site stored elsewhere. That way, if they don't get both salts, it's exponentially harder to crack (though still not impossible).
Most users use one or two passwords for all sites. So if your site is compromised, all of their credentials are as well. That's why it's imperative that you make every attempt possible at locking down your systems (including the database, and any sensitive data inside of the database)...
It depends on what else he could do once he gets a login and password. For instance the web site in question might allow him to order goods in another user's name or to impersonate that user in some other way. In other words obtaining the login credentials allows the intruder to turn a passive attack (reading data) into an active one (performing actions he shouldn't be allowed to).
There is also the problem that users commonly use the same password on multiple sites. So a security compromise in one place may compromise other things too.
For these reasons, passwords should not be stored in a database in readable form. Passwords should always be hashed (not encrypted) using a cryptographically secure hash algorithm.

What's the best method to protect login cookie data in PHP?

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.)

Whats the best way to do user authentication in php?

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

Categories