Encryption of hashed passwords? - php

I came about this security discussion after reading some topics about session management in php, have a look:
https://paragonie.com/blog/2015/04/secure-authentication-php-with-long-term-persistence#title.2
Quote from Chapter: To Pepper Or Not To Pepper?
A much better solution, which is especially useful if you employ hardware separation, is to encrypt the hashes before you insert them in your database. With this safeguard in place, even if an attacker finds a way to dump all of your database tables, they first have to decrypt the hashes before they can even begin to crack them. With the PHP and the database on separate hardware, this becomes much more secure.
In this article, the link to https://github.com/defuse/php-encryption is shared...
So far, I only used password_hash() in order to store passwords in a database. Is it recommendable to encrypt the hash itself? What's your opinion?
Thanks for your ideas!

Hashing with an appropriate hash algorithm is usually enough to protect the passwords, but it is indeed more secure to encrypt (not encode) the hashes afterwards.
When you encrypt the hashes with a server-side key, an attacker must gain additional privileges on the server, to get this key (without the key, the hashes are worthless). It is much easier to get readonly access to a database, than to get privileges on a server. Examples are SQL-injection, thrown away backups, discarded servers, ... In all this cases the encryption would protect the hashes.
In this answer you can find more information, or maybe you want to have a look at the end of my tutorial about safely storing passwords.

Is it recommendable to encode the hash itself? What's your opinion?
No, password_hash() / password_verify() is sufficient. People who need spinal-tap grade security can refer to that part of the article for guidance to avoid accidentally shooting themselves in the foot trying to improve their security, but in general if you're using bcrypt in 2016 then you're fine.
Unless you have separate servers for your website and for your database, the security gain by this strategy is zero. If I can get into your database, I can almost certainly get to your file system, and recover the encryption key.
If you do have separate hardware, and you use an authenticated encryption library such as the one provided by Defuse Security, do feel free to use it. Just know that it's not necessary for most use cases, as the password hashing API provides decent security against modern password cracking.
In a later version on PHP, they'll also support Argon2. If you're going to go overboard, switch to that instead of adding complexity to your protocol.
(Also, it's encrypt, not encode.)

there's no need at all to encrypt the hashes. The attacker has to reverse the hash to find the correct plaintext (user password). This is equivalent to find out the right key for the encryption. hashing is enough. plus salt obviously otherwise your schema is susceptible to rainbow table attacks

Related

Store Usernames and passwords in encrypted file instead of database

So i know you are going to say this is bad, but i really dont like using a database as it is confusing and hard at the same time. I also think storing usernames and passwords in a file is bad, but both the username and password would be encrypted using md5. I dont think this is secure enough though though because im going to make it public. If you could give me tips on how to make this better please tell me.
Also You will only have two attempts per minute ;)
Here is my idea: https://drive.google.com/file/d/0B19YDO3uT0ClaVZsYjRFRVZkUzA/view?usp=sharing
Also if you could give me examples on how and where to store the file in the webserver? i am not very good with php to be honest
Most databases can be accessed from the open web and you have to store the database password in a PHP file as well. Therefore in most configurations there is no security benefit using a database. It is just a more comfortable handling.
Hashing passwords is always a good idea and should be taken for granted. md5 is not a secure algorithm. Consider usage of password_hash() instead. Don't forget to intersperse a salt string to prevent rainbow table attacs when your hashfile gets stolen.
Any two-way-encryption would make your system insecure at all, because you would have to hold the secrets for decryption into plain text on the server an an attacker could steal everything he needs.
Limiting the login attemps is certainly not a bad idea, however, it is not as essential as you think. The main weak point is to get read access to the hashfile and then process an offline bruteforce, preferably with rainbow tables.
Here's what I would suggest. Don't use md5 because it's insecure and too fast without using iterations.
You really must have an SSL certificate for this to be secure from people seeing the password. Anything without a certificate is roughly equivalent to the user sending a raw text password. You have basically just changed what their password is.
As zaph noted, it's best practice to pin the certificate
On the client
send the password to the web server (encrypted by the certificate for you)
On the web server
Store a salt (a unique random string)
Hash the password using bcrypt or another secure hashing algorithm that also takes the salt
Store the salt and the hashed salted password
You need to use a password hashing algorithm that also takes a salt and iterates such that the hashing takes substantial time such as 100ms. Typically you can use algorithms such as PDKDF2, bcrypt, script or password_hash.
The password must be hashed on the server.
Use HTTPS for communication the password and pin the server certificate in the app, the pinning is important as it will protect against MITM attacks.
A DB may not be necessary, it is an issue of lookup time and disk I/O. You can start with a flat fine and migrate to a DB if/when the performance is needed. "Uncle Bob" Martin delayed using a DB in FitNesse and in the end found a flat-file solution was all that was needed.
Note: Essentially all simple hash methods such as SHA2, SHA3, etc. are to fast and need many iterations to increase the calculation time. The time is important so an attacker can not try hashed quickly. A random (not exactly unique) salt per password is needed to eliminate the use of rainbow tables of pre-calculated hashes.

Hashing authentication data in 2013

I am facing the never ending problem How to store passwords in DB?. As far as I read recently there ware a few of the previously considered safe algorithms, which had been marked as insecure. So I am struggling to find a up-to-date resource which describes the ones that are not secure any more.
I was thinking of combining two or three algos, but I remember back in the day it was considered insecure, i.e exposes the hash to attacks. The combination I was thinking of was something like that:
data_h1 = sha256(sha1(data_salt).sha1([username|email]).sha1(data_peper))
data_h2 = sha256(sha1(data_salt).sha1(user_entered_password).sha1(data_pepper))
hmac(
sha512,
data,
sha512(general_salt.data_h1.data_h2.general_pepper)
);
Where data_salt and data_pepper are constants, hard-coded in to the application, but are different than general_salt and general_pepper which are as well hard-coded constants. [username|email] is the value supplied by the user on registration and when logging in, as well as *user_entered_password* (doh!).
Will this compromise security in some way? (if no go to next)
Will there be a major bottleneck due to the hash-o-mania which will be going on in the process of generation? (go to next)
Any recommendations on the approach showed above?
My questions goes for PHP, but will be good to see what will you guys recommend and what will your comments be in general, b`cuz I do think that this is very common task, and many people still use only MD5 or SHA1 (or better yet, storing in plain text).
The main reason not to use SHA-1 or SHA-256 alone for hashing passwords is that
they are fast, relatively speaking. Password authentication is vulnerable to dictionary
attacks and brute-force attacks, since users tend to include common words in their passwords
and use relatively short passwords, making them easier to guess than encryption keys.
Hash functions like bcrypt and PBKDF2 are recommended because they are slow.
They can be tuned to take almost any amount of time; it should take as long as
possible to hash a password without causing unreasonable delay. This will help slow
dictionary attacks and brute force attacks.
However, this is not the only security consideration for password storage.
When "storing" passwords you do not actually store the password, you store its one-way hash. The reason for this is to prevent even someone with access to the system from learning a user's password. The "one way" aspect of the hash means that, while it is possible to create a hash from the plaintext, it is impossible to learn the plaintext from the hash.
In addition, all passwords should be concatenated with salt (a random sequence of digits) before being hashed. The salt value should be stored along with the hash in the database. The salt must be ROW-SPECIFIC, i.e. every password should have its own salt.
Why must hashes be row-specific? Imagine a hacker has somehow obtained a copy of your database. Normally he's up against a pretty big brute force task. If you have only one hash, the hacker can examine all the rows and find rows that occur the most frequently, because the same password + the same salt always renders the same hash. So with this information he can guess that those rows contain commonly-used passwords. He can then use that information to reduce the size of his brute force problem. Or he can try to learn one of those users' passwords and then be able to use that password on any of the other users' accounts that have the same hash. The whole point of the salt is to prevent attacks of that nature.
Use a decent one-way cryptographically secure hash with a user-specific salt. That is the standard means of storing passwords.
The addition of application-specific "pepper" (which is the same every row, and must be cryptographically random and held in a secure location) tranforms the hash into an HMAC (Hash-Based Message Authentication Code), which is even better. If someone knows your hashing algorithm and salt but doesn't know the pepper, he will have a much harder time guessing the password.

Should sensitive data be encrypted through both script and database means?

I don't know too much about encryption, but is there any benefit to encrypting the already encrypted, lets say passwords? I am aware of salts, but before this is done, does it matter or not?
Encryption is 2-way thing, when hashing is 1-way. You can decrypt encrypted sting, while you can't revert hash.
One simple, but good example is using md5 hash + salt: MD5('password' + 'random_string') - no matter PHP or MySQL you use - result is the same. So what you have here - is hash of 'passwordrandom_string', which can be unlikely matched using a dictionaries.
So every time you check the password you do:
if (md5($password . 'random_string') == $hash_from_db)
Updated: but if you really concerned about security (this usually needs to be done only if your application works with very sensitive data), and say more - you have crazy paranoia and insanity about it: there are a lot of hashing methods over the Internet. Find something with random salt (so every password can have almost unlimited amount of hashes), make few changes, combine it with other hashing algorithm - problem solved.
One thing you should know - sometimes the slower hashing works - the better. That means if you somehow have a rat-hole in login-attempts counter this will really slow down bruteforce process.
One example you can take a look on - bcrypt (it uses Java for hashing). Not saying you should use it, just an example of what you should look for.
This question has some relevant discussion on the topic. There are cases in which it would be a bad idea and could potentially weaken the encryption as pointed out in the linked thread, so you wouldn't want to do this unless you're really sure of what you're getting into.
The fundamental basis for encryption is that it's easier to encrypt (polynomial time) than it is to decrypt (non-polynomial time). The only way encryption breaks is if either/both of the following is true:
There's a vulnerability in your encryption scheme which decreases the gap between the polynomial time it take you to encrypt and the non-polynomial time you expect it to take an attacker to decrypt.
Someone has sufficient computational resources to decrypt your data (in non-polynomial time).
It sounds like there are cases where double encryption could actually make issue #1 more probable, so that's dangerous. But issue #2 seems like the bigger one to me. The idea is that an attacker with sufficient computational resources will be able to decrypt my data -- an act which implies that they're willing/able to invest orders of magnitude more computational resources to decrypt my data than I was in encrypting it.
If we accept on fiat that an attacker has the vast computational resources required to decrypt my data, the thought that they could have 2x that many resources doesn't seem unreasonable at all, to me.
And realize also that if you're using the same key, then there's really no added security whatsoever -- once they crack one, they've cracked them both. Potentially there could be value in using two different encryption techniques with two different keys to encrypt something in order to protect against issue #1 popping up for either encryption scheme, but that's surely debatable.
It depends on what you mean by encryption. If you're actually encrypting information on the database using for example Microsoft's SQL Server encryption engine, then yes it does matter. You should not rely on database level encryption as it's not really secure. The key is still stored on the machine and only prevents naive attackers who do not seek out that key along with the database.
Generally, databases also support exporting data in plaintext when the database is encrypted. This means that if an attacker gets into the system, they can just do that. If they only have the hard drives (external drive is stolen), then it saves you.
Passwords should be hashed in your application and then sent to a database, generally. It's considered secure to generate a 64 byte salt and then use SHA-512(salt || password) where || denotes binary concatenation. Don't use randomized ASCII text for salts and stick with secure random number generators such as /dev/urandom or Microsoft's CryptGenRandom. This makes it so attackers cannot store pre-computed lists of hashes for reverse lookups of common passwords.
If you want to prevent the stolen backup drive scenario you need to also make sure you are backing up your database, keeping encryption on, and storing the keys in a secure environment away from the encrypted database. We call this "separating the lock from the key". Since this doesn't help you in the situation where your database is exported, you also want to do hashing as I mentioned earlier. Hashing in addition to encryption will make it so that 1.) Attackers can't get at other less sensitive information such as names and addresses and 2.) Attackers can't even begin to attempt recovery of passwords or other credentials.
The bottom line is that it depends on your threat model.
You do get some benefits from encrypting twice using different keys. For instance, a file encrypted with weaker ciper and subsequently encrypted again with a stronger cipher and key strength will be harder to break than just having the weak cipher alone. The analogy is putting a flimsy lock box inside of a bank's vault. But, in general, you're better of encrypting with a strong cipher than encrypting twice with a weak cipher.
There are also some instances where it is appropriate for something to be encrypted twice, such as when you cross multiple trust barriers. For instance, you might encrypt your files before sending them to a cloud provider (who you may not trust). If the cloud provider needs to send files to another offsite backup company (who the cloud provide may not trust), they might encrypt it again.
That said, for passwords, you are probably better off with using a strong hash (e.g. sha1) alongside a salt for storing passwords.
Yes. It does matter. Storing sensitive data anywhere in plaintext goes beyond bad practice. It's dangerous. Even the standard md5 hash is considered "broken" now, and shouldn't be used on its own without salting it, and perhaps using other hashing combinations in tandem with it. Just to shake things up.
$salt = 'Yh%Gg^!&ud$*';
$encryption = md5(sha1($salt.md5(md5($salt.$_POST['pwd']))));
$query = mysql_query("SELECT * FROM users WHERE name=$uname AND pass=$encryption");
Not exactly the most secure, but if anybody gets their hands on the table information, they won't be able to crack it without knowing the salt and hashing combination.
Ultimately, you need to make an educated decision based on the sensitivity of the data. If you're storing user passwords of any kind, even YOU shouldn't know what they are.

What are the best practices to encrypt passwords stored in MySql using PhP?

I am seeking advice on how to securely store passwords in MySQL using PHP.
Overlooking the limitations of PHP itself, I want to know more about salting, hashing, and encrypting these bad boys.
Obviously people will continue to use weak passwords unless forced to do otherwise, but it's how I am storing them that is important to me. My user's passwords are far more important to me than the database itself, and as such I want to keep them in such a way that it will be painstaking and monotonous for any script kiddie trying reverse. Obviously with due diligence just about anything can be defeated, but I wouldn't mind making this particularly bothersome.
There are two scenarios we are looking at.
The kiddie has a complete copy of the database.
The kiddie has a complete copy of the PHP used to craft the password, and the database.
Any and all advice on this topic is graciously appreciated.
Use bcrypt. If someone has the user table of your database, then they can use brute force/rainbow tables/etc to their heart's content. Even with salt, if you're using MD5 or some other fast-hashing algorithm (which aren't designed to solve this problem, by the way); it's just a matter of time before it can be cracked.
Any well-known and widely-supported hashing algorithm is going to have this same basic "flaw" (if you can call it that; it's really by definition). The difference is that bcrypt is slow as molasses when performing the hashing operation, rendering a brute force attack much less effective.
For an absolutely great discussion on the merits of bcrypt, the dangers of other approaches, and the difficulty of password security in general, read this thread. It has lots of comments by many people that are much more knowledgeable about this sort of thing than I am, and it should hopefully help you understand more of the issues at stake.
Assuming you're using username and password as authentication tokens you can safely store the following to ensure the data can't be compromised.
Username (in plaintext)
Salt (random string)
Salted Hash (sha1(username + salt + password))
Using the scheme, an attacker cannot use rainbow tables against you and the passwords are not recoverable by any (reasonable) means. (That is, as long as your attacker isn't the government)
Even though the attacker has the salt and hash pairs it's not possible to use rainbow tables because all the possible hashes will need to be computed anyway, using the salt that they've been given, so it's a brand new brute force attack for each user.
Even with the source code and attacker won't be able to get hold of the passwords because the strength/security is in the hashing algorithm, not your code.
Combine this with using bcrypt as per Donut's answer and you're really quite safe. That is:
Username (in plaintext)
Salt (random string)
Salted Hash (bcrypt(username + salt + password))
Taking advice from here, for added fun you can dynamically change your salt as well. For example, use different salts for usernames of different length, use the user's registration date as the salt. This makes it that even if someone DOES get to your database, they can't just re-generate the hash, they have to calculate a hash table for each salt that you used.
If your users are over the internet, OpenId would be one of your best options. http://openid.net/
If your users are on your network, can you do Integrated Security?
In other words.. do not store their passwords.
Usually "salted" passwords (like with bcrypt) mean that not the password itself is stored, but only something like
salt
hash(salt with password appended)
Now if the kiddie has your database (and of course, the code - there is no point in keeping the code secret), he/she can only guess passwords, calculate the salted hash, and compare. If the hash function is expensive (like bcrypt is), than guessing is expensive too.
It's simple
store(sha256("somesalt" + password));
And nobody will be able to reverse it :)
See also: https://stackoverflow.com/questions/3897434/password-security-sha1-sha256-or-sha512

What function to use to hash passwords in MySQL?

I have a user table in my mysql database that has a password column. Currently, I use the MD5 algorithm to hash the users' password for storage in the database. Now I like to think that I am a security conscience person. I noticed while reading the MySQL docs that they don't recommend MD5 or the SHA/SHA1 hashing methods, but don't offer an alternative.
What would be the best way to hash my passwords in MySQL? A function that is natively supported in both PHP and MySQL would be ideal and necessary with my current implementation.
Thanks!
It's not necessarily that you shouldn't use MD5, as much it's that you shouldn't use just MD5, as this leaves you vulnerable to rainbow-table attacks (a rainbow table is a table of precomputed hash values - if your password is even remotely common or simple, the attacker needs merely to look up the hash and he knows your plaintext password.)
At the very least you should add a salt to every password so that any existing rainbow table is useless, forcing the attacker to generate an entire new rainbow table just for your database of passwords.
Better still is to use a different salt for every password in your database, say the username it's associated with, so that an attacker can't even generate a rainbow table for your whole database and has to crack each entry separately.
MD5 is also a very fast algorithm. Speed is the enemy when it comes to cracking - the longer it takes to generate a hash, the longer it takes for each attempt a hacker makes. Something simple like hashing the plaintext 100 times with a new additional salt each time would be barely perceptible (if at all) to a user logging in to your site, but it would increase the time it takes to brute-force a password by the same 100 times.
Far, far more detail here: http://www.codinghorror.com/blog/archives/000953.html
MD5 is considered to be weak by today's standards. It would still take some work to crack a hash made with MD5, but it's several times easier than guessing the password by brute-force. Ideally, cracking a hash should not be easier than brute-force.
SHA1 is also considered easier to crack than guessing the password by brute-force.
I actually contributed a patch to MySQL to surface the SHA224, SHA256, SHA384, and SHA512 functions from OpenSSL. These are recommended by NIST for password hashing (actually SHA256 and higher).
My patch was finished by MySQL engineers, and is included in MySQL 6.0.5 and later, if I recall.
If you use an earlier version of MySQL (and who doesn't), then you can probably use an implementation of strong hashing functions in your host language. PHP has the hash() function for example. You can do the hashing in your application and save the resulting message string to the database.
Don't forget to do salting, too!
This question is 7 years old. In that time we have progressed in computing to where MD5 and SHA1 are now easily broken by modern computers. These should be avoided now.
With PHP 5.5 came the introduction of password_hash, which uses the far more secure bcrypt algorithm. While MySQL can encrypt/decrypt bcrypt, it's a terrible solution because you're not only adding a potentially large computation load to your database layer, but the unhashed password could be stored in your logs
Under no circumstances should a plain text password hit MySQL, even if at the query level. Otherwise you risk writing the passwords to log (query log, general log, slow query log, etc). Which is horrific. So no, don't even bother...
MD5 and SHA-1 probably aren't recommended anymore due to know attacks. But, they're still generally sufficient for most use cases.
If you're looking for more options, just use PHP's hash functions -- you've got plenty of options there.
I am using a combination. For example SHA1(MD5()) is working fine.

Categories