Since the PHP sha1() can be broken quite easily by comparing against a long list of hashes - would this be any better (basically - applying sha1() over and over again to try and make brute forcing impractical by slowing the hashing process down):
<?php
$iterations = 100000;
$pass = 'hyugf67rf76dt564d5r76';
$salt = '6t6755636459679guytfugiuhbguiygfytcdtresr5tdt5yfuybiugbuyfr56d45esertdcftyuuguy';
$hash = '';
for ($i=0; $i<$iterations;$i++) {
$hash = sha1($hash . $pass . $salt);
}
echo $salt . $hash;
?>
Instead of applying the sha1 over again and again , why not implement crypt() once with a stronger - salt ?
If you have PHP 5.5 +, you could simply go for password_hash()
A userland implementation of password_hash() is also available here
HINT : You could combine the examples #4 and #3 of the password_hash()documentation link above to creater a stronger hash.
or use phpass
The preferred (most secure) hashing method supported by phpass is the
OpenBSD-style Blowfish-based bcrypt, also supported with our public
domain crypt_blowfish package (for C applications), and known in PHP
as CRYPT_BLOWFISH, with a fallback to BSDI-style extended DES-based
hashes, known in PHP as CRYPT_EXT_DES, and a last resort fallback to
MD5-based salted and variable iteration count password hashes
implemented in phpass itself (also referred to as portable hashes).
A better way to approach the problem, is by using a hashing algorithm that has this cost-intensity built-in, instead of using a custom function. If the resulting hash is not truly random, this could be a security problem.
That doesn't answer your question though, so I'll try to do that now.
Cost-intensity
If applied correctly, algorithms that are more cost-intensive make it more cost-intensive for an attacker to crack all passwords from a database. If applied incorrectly though, most of this cost-intensity can be bypassed. This is why I recommend using an algorithm that is designed to be cost-intensive, rather than trying to create something yourself.
Salts
A database-wide salt only protects you from rainbow tables without a salt. When an attacker obtains your database with passwords, and knows the salt, they can make their own rainbow table with your salt, and crack every password in the database with this rainbow table. Users with the same password have the same hash in the database.
A per-account salt (a salt that is different for each account), an attacker has to crack each password individually. Users with the same password have a different hash in the database. Cracking passwords is much more costly now.
Iteration
What you should be wary of when reapplying, is that the attacker should not be able to create a lookup table for part of this iteration. In other words: The iteration should contain something that is different for every user, and even better, different for every password tried for an user. Since you re-use the password in the algorithm, this should be no problem.*
A little change to the algorithm could however allow an attacker to bypass most of the iteration. In the following code, the attacker could create a lookup table that translates a hash to a hash with sha1 applied 99.999. In fact, such a table can be created by applying it just once on every hash, then using that lookup table multiple times. Instead of needing to apply sha1 100.000 times for every password, this now has been reduced to creating a lookup table, applying sha1 exactly once for every password, and looking up a hash in a lookup table once for every password. Even with a per-user salt, this would make no difference to the lookup table.
If you would use a per-user salt and change the line with //here to sha1($hash . $salt), the attacker has to create such a table for every unique salt in the database. This is slightly more work, but still much less than the work an attacker has to do when he has to calculate every hash for every password they try out.
<?php
#Bad code below
$iterations = 100000;
$pass = 'hyugf67rf76dt564d5r76';
$salt = '6t6755636459679guytfugiuhbguiygfytcdtresr5tdt5yfuybiugbuyfr56d45esertdcftyuuguy';
$hash = sha1($hash . $pass . $salt);
for ($i=0; $i<$iterations;$i++) {
$hash = sha1($hash); //Here
}
echo $salt . $hash;
?>
* I am by no means a security expert. I am a student with some knowledge about algorithms, and some knowledge about security, but the fact I don't see a problem doesn't mean there isn't a problem.
Related
I'm attempting to get my head around password security and salts/hashing, especially relating to PHP (with a view to storing info in MySQL).
With the following basic code, I'd like to know if I've grasped the concept or failed spectacularly!
<?php
$password = "password";
$iterations = 59999;
$salt = openssl_random_pseudo_bytes(16);
$hash = hash_pbkdf2("sha256", $password, $salt, $iterations, 20);
echo "hash_pbkdf2 (passord + salt + iteration count) = ", $hash;
echo "<br>";
echo "hash_hmac (above hash + password) =", hash_hmac('sha256', $hash, $password);
?>
What I'd like to know is;
Is openssl_random_pseudo_bytes the best way of creating a CSPRNG salt?
I realise that the salt and the two generated hashes would need to be stored in MySQL, but are two hashes needed? Is this overkill or a backwards way or combining the iteration aspect I require, along with a secure/recommended HMAC-SHA256 generated hash?
Is any of this secure by 2018 standards?
Is openssl_random_pseudo_bytes the best way of creating a CSPRNG salt?
It should be sufficient on most systems, but not always and you're not using it in a way that prevents the bad cases, so no - it's not. The best tool for the job is random_bytes().
However, you shouldn't be generating the salt on your own anyway; read below.
I realise that the salt and the two generated hashes would need to be stored in MySQL, but are two hashes needed? Is this overkill or a backwards way or combining the iteration aspect I require, along with a secure/recommended HMAC-SHA256 generated hash?
You certainly don't need 2 hashes. In particular, I have no idea why you thought you may need the HMAC. The sample code doesn't even show how you'd use that.
In fact, the iterations number in PBKDF2 refers to how many HMAC rounds it does internally, so you're kinda just increasing the iterations count by one with that (although not quite in the same way).
The reason why it needs so many iterations in the first place is because HMAC keys are not like user passwords. A key is supposed to be like a salt - random, unpredictable, raw binary data; a password is commonly easy to remember by a user, so it doesn't have the same level of entropy.
Is any of this secure by 2018 standards?
Technically, the PBKDF2 part on its own is secure when guaranteed a cryptographically secure salt. Note that I say it is technically secure and with a conditional ...
All hash_-prefixed functions are part of a generic hashing extension, yet hash_pbkdf2() is the only function in there that can create a secure password hash, and not without external aid.
Hashing has a lot of appliances and password hashing is only one of them. Creating the hash is one part, the salt - another, validation - a third; etc.
What you should be using is PHP's dedicated Password Hashing extension (refer to How to use password_hash for more info on usage), which is made specifically for what you need and is secure by design for its purpose - meaning it automates absolutely everything possible, from salt and hashing to time-safe validation.
This question already has answers here:
Best way to store password in database [closed]
(8 answers)
Closed 10 years ago.
Yes I know storing passwords in plain text is not advised.Is there a best and easy way to store passwords so that the application remains secure ??
First off, md5 and sha1 have been proven to be vulnerable 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 is sha512. sha512 is a sub-version of SHA2. SHA2 has not yet been proven to be vulnerable 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. It's 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);
A salt is usually a random string that you add at the end of all your passwords when you hash them. Using a salt means if someone 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
Hashing algorithms such as sha1 and md5 are not suitable for password storing. They are designed to be very efficient. This means that brute forcing is very fast. Even if a hacker obtains a copy of your hashed passwords, it is pretty fast to brute force it. If you use a salt, it makes rainbow tables less effective, but does nothing against brute force. Using a slower algorithm makes brute force ineffective. For instance, the bcrypt algorithm can be made as slow as you wish (just change the work factor), and it uses salts internally to protect against rainbow tables. I would go with such an approach or similar (e.g. scrypt or PBKDF2) if I were you.
Store a unique salt for the user (generated from username + email for example), and store a password. On login, get the salt from database and hash salt + password.Use bcrypt to hash the passwords.
Passwords in the database should be stored encrypted.
One way encryption (hashing) is recommended, such as SHA2, SHA2, WHIRLPOOL, bcrypt
DELETED: MD5 or SHA1. (those are older, vulnerable
In addition to that you can use additional per-user generated random string - 'salt':
$salt = MD5($this->createSalt());
$Password = SHA2($postData['Password'] . $salt);
createSalt() in this case is a function that generates a string from random characters.
EDIT:
or if you want more security, you can even add 2 salts:
$salt1 . $pass . $salt2
Another security measure you can take is user inactivation: after 5 (or any other number) incorrect login attempts user is blocked for x minutes (15 mins lets say).
It should minimize success of brute force attacks.
best to use crypt for password storing in DB
example code :
$crypted_pass = crypt($password);
//$pass_from_login is the user entered password
//$crypted_pass is the encryption
if(crypt($pass_from_login,$crypted_pass)) == $crypted_pass)
{
echo("hello user!")
}
documentation :
http://www.php.net/manual/en/function.crypt.php
You should use one way encryption (which is a way to encrypt a value so that is very hard to revers it). I'm not familiar with MySQL, but a quick search shows that it has a password() function that does exactly this kind of encryption. In the DB you will store the encrypted value and when the user wants to authenticate you take the password he provided, you encrypt it using the same algorithm/function and then you check that the value is the same with the password stored in the database for that user. This assumes that the communication between the browser and your server is secure, namely that you use https.
Let's say I have thousands of users and I want to make the passwords very secure. Now, I've learned that md5() is not the safest to use, however what I think can be done to be safe is salt it (I know this is nothing new). So for this I was thinking of creating two tables, one called accounts which will have all information associated with accounts and a table column called salt and the second table would be called something like auth and have the fields account_id, password
to start, I create a salt upon registration (generated randomly)
$salt = "#52/sBsO8";
then all the provided information goes to accounts salt being one of them
then after successfully putting the information in database, I create the password that is going to be stored in auth table, this way the password is not the md5 of the password the user enters, rather its the md5 of the salt and the password user enters
so the password in auth is
$password = md5($user_entered_password . $salt);
Test strings:
PHP Code
$password = "123";
$salt = "#52/sBsO8";
echo md5($password) ." / ";
echo md5($password . $salt);
output: 202cb962ac59075b964b07152d234b70 / dfbf0b257c5182af0ae893c2680f4594
The question is: Is this a pretty safe way of dealing with passwords? Because of md5() decrypting websites, there are so many ways to guess the passwords. And the decrypting websites don't actually decrypt the md5() they just have the md5 hashes of millions of strings.
md5 is likely to be the least safe among "popular" hashing algorithms.
Since you're using PHP, a better option would be crypt: http://php.net/manual/en/function.crypt.php
crypt($password, $salt)
For a good comparison of various hashing methods, see Jeff Atwood's post about password hashing
Excerpt about brute forcing benchmarks:
MD5 23070.7 M/s
SHA-1 7973.8 M/s
SHA-256 3110.2 M/s
SHA-512 267.1 M/s
NTLM 44035.3 M/s
DES 185.1 M/s
WPA/WPA2 348.0 k/s
the lower, the better, although DES is too short to be considered nowadays (56bit, thanks #thebod).
EDIT:
Although it isn't listed in the benchmarked methods above, the best hashing method that crypt supports is blowfish, here's an example to use it:
// $salt has to be built with exactly these components:
// '$2a$' . $2DigitsNumberAroundTen . '$' . $TwentyTwoLetters
$salt = '$2a$07$somesillystringforsalt';
crypt( $password, $salt );
Hash functions for passwords should be slow (need some computing time). Most hash algorithms are designed to be fast, but this makes it easier to create rainbow tables for every salt.
The salt should be random, and should be generated separately for every stored password. This salt has to be stored together with the hash, but is not secret (can be plain text). The salt makes dictionary attacks more difficult, and different salts make rainbow tables impracticable.
Ideally, you can adjust the computing time later for new hardware, without breaking existing hashes.
That's why you should use bcrypt to hash your passwords, it was designed especially for hashing password. And don't be afraid to use bcrypt! It is not for high security sites only, and using it can be as easy, as using an md5 hash.
It's recommended to use a well established library like phpass, and if you want to understand how PHP can generate such hashes, you can read this article.
Why do you think that this is more secure? The user types in a password. One assumes that the user is not an idiot and choses something that (s)he only knows. How is that different if that individual typed it in with the salt?
This actually makes it more insecure because if a person gets hold of the table that person has something to work on.
You are better off spending your engergies on ensuring that the computer is secure, your network is secure and teaching your users on sensible and secure passwords.
Is the following a good way to salt passwords?
hash('sha256', $_POST['password'], $_POST['email'])
I am using the user email as a salt. Some people do not use emails, some others say to use a random number.
Even if I use a random number then I will still need to store it on my MySQL table, so the salt will still be known anyway, and with the added benefit of using emails is that the possibility of rainbow tables is greatly decreased, even if I was to use a 16-bit integer?
The idea behind a salt is to prevent a hacker from using a rainbow table. For instance, if the hacker is able to compromise your database and figure out what the hashed password is he can't easily reverse engineer the hash to find a value that would generate the same hash.
However, there exist tables of already hashed words called rainbow tables. Some people have already gone through the trouble of calculating the hash of every word in the dictionary and other common passwords. If the hacker has one of these tables, plus the hashed password from your database, it makes it very easy to figure out what the password is.
However, a salt changes all that because now, instead of hashing the password, you are hashing the password plus some random value which means that the rainbow table is now useless. It does not matter if the hacker can compromise the salt.
It is perfectly fine to save the salt in clear text. You want to use something that is not uniform across all users either because, again, that defeats the purpose. I personally like to use the timestamp the account was created.
Does that make sense?
What happens if a user changes his email address? You won't be able to verify his/her password anymore because the salt value will be gone.
You shouldn't use anything as a salt that is likely to change over time. Generate a random salt (long enough to defeat rainbow tables) and use it together with the password to generate the hash.
Right now the best possible solution to use in PHP for password hashing is to use the bcrypt (blowfish) implementation. Why? There are several reasons:
variable 'work' parameter
built-in salt
Keep in mind that if you are not running php 5.3, then crypt_blowfish may not be available on your system.
Work Parameter
Blowfish/crypt is already has an expensive setup time but by setting the work factor you can increase the amount of time it takes to calculate a hash. In addition, you could easily change that work factor in the future as computers get faster and are able to compute hashes more easily. This makes the particular hashing method scale.
Built-in Salt
For me this is just laziness but I like that the salt & pass are stored together.
Implementation
To use blowfish you'd create a hash as follows
// salts must be 22 characters
$salt = "ejv8f0w34903mfsklviwos";
// work factor: 04-31 (string), each increase doubles the processing time.
// 12 takes my current home computer about .3 sec to hash a short string
$work = '12';
// $2a$ tells php to use blowfish
// you end up with a string like '$2a$12$mysalthere22charslong'
$options = '$2a$' . $work . '$' . $salt;
$hashedPass = crypt($plaintext, $options);
To verify a hashed password is simplicity:
if(crypt($user_input, $stored_password) == $stored_password) { echo "valid!"; }
Now, if at any given time you want to increase the work factor you could take the submitted pass after a successfull login, and rehash and save it. Because the work factor is saved along with the salt & password, the change is transparent to the rest of the system.
Edit
There seems to be some confusion in the comments about blowfish being a two way encryption cypher. It is not implemented as such in crypt. bcrypt is an adaptive password hashing algorithm which uses the Blowfish keying schedule, not a symmetric encryption algorithm.
you can read all about it here: http://www.usenix.org/events/usenix99/provos.html
or you can read even more about using bcrypt (the hashing implementation of blowfish) here: http://codahale.com/how-to-safely-store-a-password/
i suggest using iteration such as below. The crypt could be replaced with md5 or any other hashing algorithm. the 10 could be any number.
$pass=mysql_real_escape_string($_POST['pass']);
$iterations = 10;
$hash = crypt($pass,$salt);
for ($i = 0; $i < $iterations; ++$i)
{
$password = crypt($hash . $pass,$salt);
}
In addition, you could add any other variable. I hope this solve the problem
You could use this:
$salt='whatever';
$a=hash('sha256', $_POST['password'], $salt);
$b=hash('sha256', $_POST['email'], $salt);
$hash=$a.'-'.$b;
When the user changes the email, just do:
$old_a=substr($old_hash,0,strpos($old_hash,'-'));
$new_b=hash('sha256', $_POST['email'], $salt);
$new_hash=$old_a.'-'.$new_b;
What are the advantages / disadvantages of those 3 methods to create a salt?
$salt = md5($password);
$salt = sha1(md5($password));
$salt = generate_random_number();
Computing hash:
$hash = sha1($salt + $password);
Salts
To answer this question it's important to know for what salts are.
Salts are designed against attacks with pre-calculated tables. For example rainbow tables. Rainbow tables are huge tables with all possible password variations up to a certain length. (Using a clever memory/time tradeoff.)
If the attacker only wants to crack a single password, they don't offer an advantage.
The statement above is not true if
The database doesn't use salts. Then a common rainbow table can be used.
The salt is too short. If the salt is too short, it has the same effect as just having a longer password.
It's a common salt like salt. There are for sure already some rainbow tables with that salt included.
Attackers using rainbow tables usually want to crack as many accounts as possible.
Which of your methods is most secure?
All of your methods except the third are insecure. This is because using any of the other methods allows the attacker to calculate a rainbow-table for your whole database.
Because the salt is dependent on the password. Don't make it dependent on the username either, this would still allow an attacker to create a rainbow table for the 100 most common usernames.
Keep in mind
Use only a cryptographically secure random generator to calculate your salts.
Don't use MD5. It's already considered broken, use at least SHA1.
The first two methods are worthless. The whole point of salting is that the same password does not always result in the same encrypted/hashed string.
If you make the "salt" dependent on just the password, the same password will always result in the same hash. So basically the result is the same as if you'd use a slightly different hash function without any salt.
With the third method two users with the same password will usually get a different salt and the hashed version of the password will look different for both users. It will be hard to tell by the hashes that they both have the same password.
Well strictly speaking you only have one salting method, where you calculate the hash. The first three lines are different ways of generating a salt.
So a salt is there to stop precomputed lookup tables from discovering passwords. It should be a fixed value stored someone that is, preferably, unique to the plain text being hashed.
The most secure would be to use a cryptographically secure random number generator to produce a salt which is then stored along side the password.
If you created a salt which was an MD5 of the password then it would have to stored alongside the hashed and salted password value, which means you have an unsalted hash which is vulnerable to precomputed lookup tables, unless you plan to calculate it every time which is a small performance hit. By taking a SHA hash of an MD5 hash you're reducing the possibility of the plain text values, as there's a finite number of MD5 hash values as they are fixed length. This would mean that a rainbow table lookup might have a greater chance of success than a truly random salt.
So use the random salt please.
A useful way to think of rainbow tables is that they can be built for any one-way (or "trapdoor") function that only has one input. That is, if you use the same function, F, for all your passwords: hash = F(password). F could be MD5 or SHA1 or whatever.
Now lets look at salts. You use a salted function G, hash = G(salt, password). If all passwords in your database use the same salt, you can construct a function G, where G(password) = F("your salt", password), so there is a single input function, and thus you can build a rainbow table.
What if the salt depends on the password? Say the salt = I(password), we can build J(password) = G(I(password), password), a single input function, so rainbow tables can be built.
So, each password needs to have its own salt. This means that in the time it would take an attacker to crack all of your passwords, they can only crack one.