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.
Related
Let's say I've got an application where my "administrators" are able to see the regular users passwords easily. They can even change it, if they need to.
When a new user comes, the "admin" adds the user to the "system", and gives him the password he just typed. Then the user may change it.
If the user forgets his password, he asks the "admin", whose will be able to see it and tells him.
In that application, let's say the passwords are stored in files which are stored in a directory.
The "administrators" are using (let's name it easily…) "admin.php" to access to their administration interface.
Is it safe to choose not to encrypt the passwords but to chmod the directory to "0700", so that only the "admin.php" script can access/modify it?
If not, can you tell why it is not safe to store it in a "0700" folder?
Is a SQL database safer than a "0700" folder?
What is the best way to do?
The point of hashing passwords is so that nobody except the user themselves can know the password. Because the password is supposed to be secret, and the secrecy of that piece of information is the only form of security the user has.
By storing passwords in plaintext, you make it possible for people other than the actual user to know the password. That replaces the security of mathematical certainty (or at least probability) with the security of human fallibility, system configuration and business procedures. At least one of which is more likely to fail than math.
If your admins are reading the password back to users over the phone, they have basically already failed the procedure part. Sounds like your organisation isn't treating passwords as a form of security, but an inconvenience to work around to begin with, so… whatever I guess? ¯\_(ツ)_/¯
This isn't save at all. You should always use salted password hashing. There isn't a single excuse not to hash passwords.
Safe is a relative word. There's a degree of safety in that an admin's privilege level or a system acts as a security measure because it's a barrier to accessing that directory. Bypassing either of those grants direct access to those passwords, whereas that wouldn't be the case if they were hashed. Hashes are one way functions. Meaning that you can't derive the password unless you perform a rainbow table attack, which along with those two security barriers, further increases the attack cost for an attacker. And that, from an Information Security standards standpoint is a good security practice. That said, hashes aren't absolutely safe either. There are databases out there with hashes so the rainbow table cost can be avoided. So overall, it's less safe because they aren't using standard security practices.
I'm trying to create a cookie to keep my website's users logged. I let the person log in from multiple devices. Well can I create one identical cookie for all user's devices? Or should I store multiple different cookies for different devices (and why)?
Actually I don't see any problem with having one common cookie for an specific user on multiple devices. Also that cookie isn't changeable. That will be always fixed until the user changes his password. I create that cookie like this:
md5($password.$user_id.$username);
That cookie is based on the password because I want to log-out him when he changes his password, otherwise he will be logged into all devices that he already logged.
Am I doing that right correct?
The cryptographic hash algorithm MD5 has already begun to be broken, mainly in regards to its collision resistance property, as well as preimage resistance slightly. See the Wikipedia article, in the security section.
Therefore I would not use MD5 for anything slightly security related. A similar story with SHA-1 in that it has began to be broken, so I would use SHA-2 if you do indeed need a hashing algorithm.
The problem with your approach is that you cannot revoke the token from individual devices easily. Also having password as input to your algorithm could make it vulnerable to a hash cracking attack, should the other values be known. Don't rely on your method being secret either, Kerckhoffs's principle states "A cryptosystem should be secure even if everything about the system, except the key, is public knowledge.".
Also another problem with your approach is that your hashing algorithm needs plaintext access to the password, which could suggest you are storing passwords insecurely. In short ensure you are using bcrypt for password storage. Of course, you may be creating the cookie and storing a server-side version of it at a point where the user enters their password, however given that you want to invalidate cookies automatically upon password change makes me think not.
The most secure way to manage devices with tokens is to generate a 128-bit random token per device, and store this hashed with SHA-2 in your database. Ensure a CSPRNG is used to generate the token.
Therefore:
Cookie value: 128-bit token
Database value: SHA-2(128-bit token)
Note that salts are not required for values of such bit strength. Then when a user changes their password, you simply delete all server-side tokens for the user. Additionally, you will be able to allow the user to revoke tokens for different devices individually without any password change required.
The reason for hashing on the server-side is to mitigate any session hijacking should an attacker gain access to your sessions table.
Am I doing that right correct?
Unfortunately no.
By creating cookies with this design: md5($password.$user_id.$username), you are implementing them in their most naive approach. A basic rule of thumb is to never store user's credentials within a cookie. This is valid for whatever powerful the hashing algorithm you use may be. And for the MD5 algorithm you are using, it is not that strong (Transcript Collision Attacks: Breaking Authentication in TLS, IKE, and SSH)
Or should I store multiple different cookies for different devices
(and why)?
You do not have to. Useless. And as a good security principle, never add functionality (code) to your software if you do not need it otherwise you may enhance the attack surface.
Summarizing question
What arguments are there for or against saving password hashes in the session?
Idea
Store the password hash (as it is in the DB) in the session upon login and validate it against the DB hash on each access in order automatically invalidate all sessions on password change.
My thoughts
These are my thoughts so far on the subject.
Pro
Assuming two people legitimately share an account it would (mostly) prevent a sort of racecondition of both changing the password while the other is logged in. Confusion would only occur once and not twice.
Assuming a malicious attack the legitimate user could kick out the attacker if detected early enough.
Con
Possible dataloss if person A submits a form right after person B changed the password.
Assuming a malicious attack the attacker can kick out the legitimate user.
Neutral
No real performance impact. (Edit: Because I load the userinformation on each pageload anyway for other reasons.)
Security issues are almost non existant. If someone has access to the server the effort of accessing the database which has all the hashes is comparable to the effort of accessing the session store, which has the hashes of the loggedin users.
Answers and Comments please
I don't want to start a subjective discussion here. I would like to collect (as objective as possible) pros and cons on that subject. What have I not considered yet?
Edit:
Clarification: The idea of invalidating all sessions (except the session used for changing the password) came from the thought of "If one person changes the password without telling certain other people there is a reason for that, thus they should immediately loose access.", assuming there are no malicious users (what a wonderfull world that would be...).
The scenario about simultaneously changing the password sounds extremely rare and not a core premise to build a session architecture around. The scenario can also be better prevented with optimistic locking and other concurrency solutions.
You can invalidate sessions when a password is changed explicitly, you don't need to store the password in the session for that. This is trivial if you use a database to store sessions (preferably an in-memory database like Redis or memcached), but it's not impossible using standard PHP file-based sessions either. Just proactively nuke all active sessions by the given user when the password is changed, done.
The password is a secret and should stay out of circulation as much as possible. The hash is just a shadow of that secret, but even it you should keep secret. Storing it in the session is one step closer to accidentally leaking it than it would be when keeping it purely in the database.
There is a performance impact of doing a database lookup on every single page load.
Suggestion:
Instead of storing your password hash at session, you can generate a "token", here you can generate a random sequence of characters and numbers, and store it at the session and give it a expiration time.
Let's suppose you and I share an account with password cow123. When I get logged in, i will receive token $124abc and you a token %xyz222, both tokens are related to password cow123.
Now you changed the password cow123 to cat321.
Nothing will happen to me because my token is still valid (You can create a table to persist valid tokens with expiration date column)
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.
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