I'm the developer of a new website built in PHP and I'm wondering what exactly is the best
thing to use for hashing. I've looked at md5 and sha1 but is there anything more secure.
I'm sorry if this is a nooby question but I'm new to PHP Security and I'm trying to make my
site as secure as possible. Also what is a salt?
Thanks,
Waseem
First off md5 and sha1 have been proven to be vunrable to collision attacks and can be rainbow
tabled easily (When they see if you hash is the same in their database of common passwords).
There are currently two things that are secure enough for passwords, that you can use.
The first being sha512. sha512 is a sub-version of SHA2. SHA2 has not yet been proven to be
vunrable to collision attacks and sha512 will generate a 512 bit hash. Here is an example of
how to use sha512:
<?php
hash('sha512',$password);
The other option is called bcrypt. bcrypt is famous for its secure hashes. Its
probably the most secure one out there and most customizable one too.
Before you want to start using bcrypt you need to check if your sever has it enabled, Enter
this code:
<?php
if (defined("CRYPT_BLOWFISH") && CRYPT_BLOWFISH) {
echo "CRYPT_BLOWFISH is enabled!";
}else {
echo "CRYPT_BLOWFISH is not available";
}
If it returns that it is enabled then the next step is easy, All you need to do to bcrypt a
password is (Note for more customizability you need to see this How do you use bcrypt for hashing passwords in PHP?):
crypt($password, $salt);
Now to answer your second question. A salt is usally a random string that you add at the end of
all you passwords when you hash them. Using a salt means if some one gets your database
they can not check the hashes for common passwords. Checking the database is called using a rainbow table. You should always use a salt when hashing!!
Here are my proofs for the SHA1 and MD5 collision attack vulnerabilities:
http://www.schneier.com/blog/archives/2012/10/when_will_we_se.html, http://eprint.iacr.org/2010/413.pdf, http://people.csail.mit.edu/yiqun/SHA1AttackProceedingVersion.pdf, http://conf.isi.qut.edu.au/auscert/proceedings/2006/gauravaram06collision.pdf and Understanding sha-1 collision weakness
The whole purpose of the salt is to slow down an attacker from comparing a list of pre-generated hashes against the target hash.
Instead of needing to pre-compute one "hashed" value for each plaintext password, an attacker needs to precompute 16384 "hashed" values for each plaintext password (2^7 * 2^7).
That kinda pales today but was pretty big when the crypt function was first developed - the computational power to pre-compute that many passwords times the number of plaintext password you suspect (dictionary) was pretty high.
Not so much today which is why we have things like shadow passwords, other core password functions besides crypt and every sysad wanting you to pick a password that would not show up in a dictionary.
If the hashes you want to generate are for passwords this is a well accepted method of implementing it.
http://www.openwall.com/phpass/
If you're planning to do this for passwords, then do not use MD5 or SHA1. They are known to be weak and insecure, even with salt.
If you're using them for other purposes (eg providing a hash of a file to confirm its authenticity, or a random hash database column to provide a pseudo-random sort order) then they are fine (up to a point), but not for passwords or anything else that you would consider needing to be kept secure.
The current best-practice algorithm for password hasing is BCrypt, with suitable salting.
And the best way to implement BCrypt password hashing in PHP is to use PHP's new password API. This API will be featured as a set of built-in functions in the next version of PHP, v5.5, due for release in the next few months. The good news is that they have also released a backward-compatibility version for users of current versions of PHP (5.3 and 5.4), so even though PHP 5.5 isn't released yet, you can start using the new API immediately.
You can download the compatibility library from here: https://github.com/ircmaxell/password_compat
Also: You asked what "salt" is. Since I've mentioned it a couple of times in this answer, I should address that part of the question too.
Salt is basically an additional string added to the password when hashing it, in order to make it harder to crack.
For example, an attacker may know in advance what the hashed value is for a given password string, or even a whole lot of given password strings. If he can get hold of your hashed data and you haven't used a salt, then he can just compare your hashes against his list of known passwords, and if any of your users are using an easy to guess password, they'll be cracked in seconds, regardless of what hashing method was used.
However, if you've added a secret extra string to the password when you hash it, then the hashed value won't match the standard hash for the original password, thus making it harder for the attacker to find the value.
The good news is that if you're using the API I mentioned above, then you don't need to worry too much about the details of this, as the API handles the salting for you.
Hope that helps.
Related
Use SHA512 as encryption in Multicraft panel (which you can change the settings for MD5), but I need to use an older version of the same database. This old version did not have the option to encrypt with SHA512, but only with MD5. Thus, all passwords are invalid with MD5.
It's possible convert all SHA512 passwords in MySQL database to MD5?
SHA512 and MD5 are hashes, not encryption algorithms. By design, they are not reversible.
The only way to convert these values is to wait for each user to log in, validate their password against the existing SHA512 hash, and rehash¹ their input with MD5. This is the reverse of how password hashes are updated to more secure standards.
But please, please, don't do this. MD5 is hopelessly broken. You would be doing your users a huge disservice to revert from SHA512 to MD5. Find a way to use the newer version of your software.
¹As noted by zaph in a comment, "rehashing" is an oversimplification, and depending on how your panel is actually implemented it might be using insecure password storage today.
To provide reasonable security each password must also have a unique random salt (which protects against things like rainbow tables) and each hash must be iterated enough times to make brute forcing impractical. As computers get more powerful the number of iterations must be increased. Today it is common to iterate tens or hundreds of thousands of times.
Cryptography is shockingly difficult to get right. Instead of trying to follow all the best practices manually, use libraries and functions that operate at the right level of abstraction and have been audited for security. An algorithm like bcrypt (via PHP's built-in password_hash function, where it is currently the default algorithm) would be a good choice.
Short answer: No.
Long answer:
By design, both MD5 and SHA512 are one-way hashes. In order to convert SHA512 to MD5, you would need to know both the original password for every password your are trying to convert, and also the salt that was used to encrypt them. You almost certainly wouldn't know every password for every one of your users.
One-way hashes work by actually casting the same algorithm every time a user logs in. The user types in their password, the algorithm is applied to it, and if it perfectly matches the copy in the database that has already been hashed, then the user is logged in. You can't use any sort of algorithm to work out what the original password was, only to compare if the output of applying a specific password would be to a password that is already encrypted.
MD5 is also a far weaker hashing algorithm than SHA512. Converting to MD5 would make your password far less secure, and this would be something that you probably wouldn't want to do. Instead, you should be looking at a way to incorporate the new database system.
I understand that bcrypt is more secure than other methods but still puts you the same situation where you need to salt passwords!
If the salt is included in the hash string it's not needed to store it separately in the DB. Everytime I need to create a new hash, meaning a new salt as well, do I have to get all the passwords, extract the salts and check the new one doesn't exist already against my DB passwords?
Wouldn't be easier to store directly the salts separately for easy compare? If yes then I don't get:
the point of storing the salt in plain text
why bcrypt is more secure than manually use sha256 with salted passwords
I'm actually going to disagree with Curtis Mattoon's answer on a couple of things.
When you hash using bcrypt, the salt is stored directly inside the hash, so you don't need to store it separately. I'm not sure what he means by not having to store it at all, because the hash without the salt is completely useless. The salt is needed to verify the password against the hash.
I agree on this point. If you are updating one password, you don't need to update them all. In fact, it would be impossible because you (hopefully) don't know the passwords for any other users.
You don't need to go through pains to get a unique salt. If that were the case, you could use uniqid, but the problem with that is its output is predictable. Predictability is a bad thing in cryptography. Instead, what you want to do is use a pseudo random salt as close to random as possible (i.e. using /dev/random instead of /dev/urandom). If you have a billion users, you may get one or two that have exactly the same salt, but seriously, is this such a big problem? All it does is doubles someone's chance of brute forcing the password for those two particular passwords out of a billion, and I doubt it's even that high of a chance of a collision occurring. Don't strain yourself over this. Make the salts random, not unique. Using things like last login time or IP address is only going to take away from randomness.
As for a comparison between SHA512 and Blowfish, see here SHA512 vs. Blowfish and Bcrypt
This site seems to do a decent job at a brief explanation: http://michaelwright.me/php-password-storage
Quick answer:
1) You don't need to store the salt.
2) You don't need to update all the hashes, if you use a unique salt for each password.
3) I'm no crypto expert, but when you're using a unique salt for each user/password, an attacker would have to use a different set of rainbow tables for EACH user. Using the same salt value across the site means that every user's password would be susceptible to the same hash tables. In the past (for better or worse), I've used a function of the user's last login time and/or last IP as the for their password's salt.
e.g. (pseudocode) $password = hash(hash($_POST['password']) . hash($row['last_login']));
4) I'll defer the "Why is bcrypt better?" question to someone more knowledgeable about such things. This answer may help: How do you use bcrypt for hashing passwords in PHP?
I know that there are alots of questions about this subject but i really need to ask this.
Today I've been working on encrypting passwords with md5.
So what I've done is.
I got 4 salts. (they changes depending on user values)
from email id and substr then md5 them
from email and id substr other positions
a long string, substr it and then md5 it
another long string, substr it and then md5 it
Then i md5 salt1 and 3 and the password with salt 2 and salt4
After this I have to change the password automatically whenever a user changes his email or his id getting changed.
What do you guys think about this?
Nothing.
MD5 is broken and bad.
Using the mailaddress as salt is a good idea. But using md5 is not. Use instead bcrypt, scrypt or pbkdf2.
Don't invent your own ecryption, unless you really know what you are doing, and trust me, you don't
First, let us define a few terms.
Encryption is when you encode a message so that it cannot be read. Encryption involves a plaintext, a cipher and a key. It is like putting a book (the plaintext) in a locked room (cipher), which can only be opened using a known tool (a key). There are many kinds of encryption, but that is a simple description. Encryption is two-way, meaning that you can encode and decode the message.
Cryptographic hash is when you take any kind of data and generate a fixed size value for it (usually called a hash or a digest). Cryptographic hashes are one-way, which means that you cannot reverse the process.
A salt is a unique string, or a collection of bits, similar to a nonce (a unique number that is only used once). Salts are only used to make it infeasible for a cracker to process a list of hashes. They are not supposed to be used as a secret (i.e. like a cryptographic key). The only reason people usually talk about randomness when it comes to salts is because they want to generate a unique salt (if the randomness is not great enough they may get colliding salts, for instance).
Okay, now to how you should hash a password.
A relatively safe way of hashing a password is to simply tack on a unique hash onto a password, and then save the salt with the password:
$pass = 'this is my password';
$salt = uniqid('', true);
$hash = sha1($pass . $salt);
// INSERT INTO users ('hash', 'salt') VALUES ('$hash', '$salt') WHERE ...
That is an okay way of doing it if your website does not retrieve any sensitive data from its users.
If you deal with sensitive data, or if you just want to make sure that you are doing everything you can to keep stuff safe, then there is a PHP function that does the hashing for you. It is called crypt() (read the documentation to learn how it works). Here is an example of how to hash a password using the function:
$pass = 'this is my password';
$salt = 'unique string';
$hash = crypt($password, '$2y$07$'.$salt.'$');
echo $hash;
That will securely hash a password.
The thing to realize is that the crypt() function is much more secure than anything you can come up with (unless you are a specialist in the area).
In newer versions of PHP (5.5.0+) there is a password hashing API that makes it even simpler to hash a password.
There are also various hashing libraries out there. PHPass is a popular one.
It is bad, because it uses MD5.
MD5 is a very fast operation. It can be executed billion of times per second on graphic cards hardware. It is considered bad practice to use it for any password related things.
Use bcrypt. Use a random salt. Use the upcoming PHP API for hashing, verifying and rehashing passwords. This include file implements it for versions starting with PHP 5.3.7: https://github.com/ircmaxell/password_compat
Well, "MD5 is broken and bad" is a little exagerated. Even if it can be brute-forced with a lot of CPU, it is not "broken" and is still a very useful algorithm for a lot of things involving hashing.
So "MD5 should not be used for password encryption" sounds much better to me.
When using PHP, an easy and safe option is to rely on the password_hash() (which natively generates a random salt) and password_verify() functions.
The advantage is that the encryption algorithm will transparently be updated with each new PHP version (at the moment PASSWORD_DEFAULT is set to bcrypt, but should bcrypt be "broken" it can be set to a newer algorithm), which makes any code using those functions quite resilient.
I personally do not recommend involving of the user id and his email into the hashing of his password.
You can deal with the password by:
Dynamic salt per user based on random string generated on user registration
Prepend one part of the salt and append the other around the password
Double md5: md5(md5($password))
Etc.
a simple way would be to generate a random salt for each user and hash your password like this
public function encodePassword( $raw, $salt ) {
return hash('sha256', $salt.$raw);
}
For high security hash, you can check this link which explain how to implement PBKDF2:
http://crackstation.net/hashing-security.htm#phpsourcecode
I realize that this topic have been brought up sometimes, but I find myself not entirely sure on the topic just yet.
What I am wondering about how do you salt a hash and work with the salted hash? If the password is encrypted with a random generated salt, how can the we verify it when the user tries to authenticate? Do we need to store the generated hash in our database as well?
Is there any specific way the salt preferably should be generated? Which encryption method is favored to be used? From what I hear sha256 is quite alright.
Would it be an idea to have the hash "re-salted" when the user authenticates? And lastly is it any major security boost to rehash it a bunch of times?
Thank you!
The answer is to not do it yourself. The one-liner that will do everything you need in PHP is to use bcrypt.
Read this, it's easy to understand and explains everything you asked: http://codahale.com/how-to-safely-store-a-password/
bcrypt takes into account the hashing by itself, and can be configured to be as "complex" as necessary to maintain the integrity of your users' passwords in the event of being hacked.
Oh, and we don't "encrypt" passwords, we hash them.
You need to store both the hash and the salt that has been used to calculate the hash.
If you then want to check if an input is equivalent to the original input value, you can re-calculate the hash with the same salt and compare the stored hash with the new calculated one. If they are equal both input values are identical (up to some particular probability).
The choice of hashing algorithm is also important. Because there are fast hashing algorithms and rather slow hashing algorithms. And as you want to make is hard to find a collision (at least in brute-force), use a slower hashing algorithm.
What I am wondering about how do you
salt a hash and work with the salted
hash? If the password is encrypted
with a random generated salt, how can
the we verify it when the user tries
to authenticate? Do we need to store
the generated hash in our database as
well?
Yes. First you generate a salt, then generate a hash from the password plus the salt and save both hash and salt together.
Is there any specific way the salt
preferably should be generated?
I doubt that there's consensus on what's preferable. I use /dev/random. e.g.
$salt = '$2a$12$'
. strtr(substr(base64_encode(shell_exec(
'dd if=/dev/random bs=16 count=1 2>/dev/null'
)), 0, 22), '+', '.')
. '$';
$hash = crypt($input, $salt);
Which encryption method is favored to
be used? From what I hear sha256 is
quite alright.
See Computer Guru's answer, i.e. use bcrypt as in the example above. See the PHP manual page on crypt(). If bcrypt isn't on your system, one way to get it is the Suhosin patch.
Would it be an idea to have the hash
"re-salted" when the user
authenticates?
The salt just makes dictionary attacks slower. If you have a decent random salt to start with I wouldn't think changing it frequently would help. You'd probably be better off investing your effort in making users choose good passwords, changing them often enough and keeping your Blowfish cost parameter at a sensible value.
And lastly is it any major security
boost to rehash it a bunch of times?
That question belongs in the world of cryptographic design. I recommend you leave that to the experts. In other words: forget it—just use best common practices.
What generally you do is something like:
salted = HASH(password . key); // DON'T DO IT LIKE THIS
Where key is "the salt" - the secret key stored in configuration files. So in order to crack the password you would need both the secret key and the DB so it is good to store them
in separate places.
Because the schema I had shown is not strong enough, it is better to use HMAC for this purpose rather then hand written salting. Such an operation is as simple as hash and PHP supports this.
salted = hash_hmac('sha1',password,key); // <-- this is ok
See this: http://php.net/manual/en/function.sha1.php
Three simple rules. Okay, five:
Most important thing, if you want to consider your password storage being safe: allow strong passwords only e.g. at least 8 chars with some different case letters and numbers and even punctuation marks
Allow users to use strong passwords only. Make a routine to check length and character range and refuse weak passwords. Even get yourself John the ripper database and check against it.
Torture users wickedly, beat them up, until they choose good long and random enough passwords. Passwords! Not salt, of which everyone is delighted to talk for hours, but password itself should be random enough!
Salt your passwords and store that salt along with user info. you can use user email and username as a perfect salt, no need to invent something extraordinary random.
Certain algorithm is not that important, you can use MD5 as well. In real world there are very few people who would bother themselves with cracking user database of your famous Fishing And Grocery Fans Society site forums.
What is the fastest, yet secure way to encrypt passwords (in PHP preferably), and for whichever method you choose, is it portable?
In other words, if I later migrate my website to a different server, will my passwords continue to work?
The method I am using now, as I was told, is dependent on the exact versions of the libraries installed on the server.
If you are choosing an encryption method for your login system then speed is not your friend, Jeff had a to-and-frow with Thomas Ptacek about passwords and the conclusion was that you should use the slowest, most secure encryption method you can afford to.
From Thomas Ptacek's blog:
Speed is exactly what you don’t want in a password hash function.
Modern password schemes are attacked with incremental password crackers.
Incremental crackers don’t precalculate all possible cracked passwords. They consider each password hash individually, and they feed their dictionary through the password hash function the same way your PHP login page would. Rainbow table crackers like Ophcrack use space to attack passwords; incremental crackers like John the Ripper, Crack, and LC5 work with time: statistics and compute.
The password attack game is scored in time taken to crack password X. With rainbow tables, that time depends on how big your table needs to be and how fast you can search it. With incremental crackers, the time depends on how fast you can make the password hash function run.
The better you can optimize your password hash function, the faster your password hash function gets, the weaker your scheme is. MD5 and SHA1, even conventional block ciphers like DES, are designed to be fast. MD5, SHA1, and DES are weak password hashes. On modern CPUs, raw crypto building blocks like DES and MD5 can be bitsliced, vectorized, and parallelized to make password searches lightning fast. Game-over FPGA implementations cost only hundreds of dollars.
I'm with Peter. Developer don't seem to understand passwords. We all pick (and I'm guilty of this too) MD5 or SHA1 because they are fast. Thinking about it ('cuz someone recently pointed it out to me) that doesn't make any sense. We should be picking a hashing algorithm that's stupid slow. I mean, on the scale of things, a busy site will hash passwords what? every 1/2 minute? Who cares if it take 0.8 seconds vs 0.03 seconds server wise? But that extra slowness is huge to prevent all types of common brute-forcish attacks.
From my reading, bcrypt is specifically designed for secure password hashing. It's based on blowfish, and there are many implementation.
For PHP, check out PHP Pass
For anyone doing .NET, check out BCrypt.NET
It should be pointed out that you don't want to encrypt the password, you want to hash it.
Encrypted passwords can be decrypted, letting someone see the password. Hashing is a one-way operation so the user's original password is (cryptographically) gone.
As for which algorithm you should choose - use the currently accepted standard one:
SHA-256
And when you hash the user's password, be sure to also hash in some other junk with it. e.g.:
password: password1
salt: PasswordSaltDesignedForThisQuestion
Append the salt to the user's password:
String s = HashStringSHA256("password1PasswordSaltDesignedForThisQuestion");
Whatever you do, don't write your own encryption algorithm. Doing this will almost guarantee (unless you're a cryptographer) that there will be a flaw in the algorithm that will make it trivial to crack.
I'm not necessarily looking for the fastest but a nice balance, some of the server that this code is being developed for are fairly slow, the script that hashes and stores the password is taking 5-6 seconds to run, and I've narrowed it down to the hashing (if I comment the hashing out it runs, in 1-2 seconds).
It doesn't have to be the MOST secure, I'm not codding for a bank (right now) but I certainly WILL NOT store the passwords as plain-text.
Consider to use bcrypt it is used in many modern frameworks like laravel.
Use this function when inserting in database
Password_harsh($password,PASSWORD_DEFAULT);
And when selecting from the database you compare the password you are inserting with the one in the database using the function
if(password_verify($password,$databasePassword)){
}else{
echo "password not correct";
}
This will harsh the password in a secure format
password_hash ( string $password , int $algo [, array $options ] ). (PHP 5 >= 5.5.0, PHP 7)
password_hash() creates a new password hash using a strong one-way hashing algorithm. password_hash() is compatible with crypt(). Therefore, password hashes created by crypt() can be used with password_hash().