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.
Related
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.
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
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Secure hash and salt for PHP passwords
WARNING Don't use MD5 for passwords, use an alternative like bcrypt
For my passwords should I use salt like this (the salt will be unique to each user and not stored directly with the password)...
$salt = sha1(md5("coders gonna code"));
$password = md5($salt.$password);
or would it be okay if I just used:
$password = md5($password);
because if I used salt, even if the user makes up a bad password like password it won't matter because the salt (in this case) would be 145ac26ff093c6e1317f7d5fb4c9fd11c77be975 so the entry for there password would be 145ac26ff093c6e1317f7d5fb4c9fd11c77be975password which according to http://howsecureismypassword.net/ it would take 3 octodecillion years to crack.... so opinions? Or should I be even worse and go
$password = md5($salt.$password.md5($salt));
If the person has gone far enough to get the salt hash, would anything be able to stop then going futher? < More of a statement this last password
To everyone who said I should do it per user... I know, this is just an example.
You should change the salt so that it is specific to each user, not a system wide constant. This will make rainbow table attacks against your password hashes much more inconvenient.
There is a good write up on the evolution of salting in this article by Troy Hunt.
Edit
$salt something unique to each password record, which adds much entropy to it. This is usually a random sequence of bytes, stored with the user account.
Hashing is traditionally done on the concatenation of salt + password.
$passwordHash = hash($salt.$password);
As others have said, don't use MD5 for hashing. It is broken.
Applying additional proprietary algorithms to password or salt prior to hashing is not recommended. Instead, look at an industry strength solution such as PBKDF2, which, in addition to salting, also requires many (typically > 10k) repeated iterations which will further slow down an attacker.
If you adopt OWASP guidelines, the number of hashes performed should be increased regularly (to counteract Moore's Law). The number of hashes should also be persisted per user, meaning you will need to store the triple of hashed password, salt, and number of iterations.
You are using the salt totally incorrectly. Salts should be unpredictable; your salt is the exact opposite of that (fixed). Since a fixed hash is of absolutely no benefit, it also seems that you are counting on the salt not being known by the attacker. This is the definition of security through obscurity, which is another bad practice.
What you should be doing is:
Use an unpredictable string of reasonable length as the salt. Randomly generated 8-character strings from a pool such as lower/upper case letters and digits are fine.
Use a different salt for each user, and change it every time they change their password.
Move from MD5 (which is considered broken) to another hash function better suited to this application. SHA-1 is better because it's not considered broken; bcrypt is the best because it has a configurable load factor.
Don't use MD5 as your hashing algorithm, use something more secure such as SHA256 or even bcrypt.
Definately salt the password, if someone did gain entry to your database they would not be able to reverse the passwords for common hashes or using techniques such as rainbow attacks.
http://michaelwright.me/php-password-storage
http://en.wikipedia.org/wiki/Bcrypt
First of all you should never store md5 directly, which you regognized already.
PHP 5.5 will bring new methods to easily create and verify passwords in 1 line, until then you can use https://github.com/ircmaxell/password_compat (forward-compatible) to generate & verify safe password hashes.
I think salt is understood here incorrectly. The idea of salt is that it should be unique per hash. The reason is that when you create hash some different strings may have the same hash.
In your example you're hashing password too so it won't look like: 145ac26ff093c6e1317f7d5fb4c9fd11c77be975password
P.S. Use bcrypt. It's much more reliable.
Salts are meant to be completely random, and unrelated to the actual password you are storing a hash of.
What you should really do is generate a completely random salt, then do
$password = md5($salt.$password);
and store the user's username, salt and hashed password.
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 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.