Related
I've been reading about password hash functions and it's said: use a salt to make harder the hacker's work, use a height cost algorithm, etc
I've found this password_hash function but... it returns this (letters are an example to explain)
AAAACCCSSS....SSSHHH.....HHHH
Example:
Where:
AAA is the algorithm
CCC is the cost
SSS....SSS is the salt
HHH.....HHHH is the hash we get
It is supposed (I think) that the algorithm, cost and salt is used to make the life harder to hackers, and if I use that my hash will be safer
But, what happened if I use all of them but I say to the hackers that I'm using this salt, algorithm and cost?
Doing that I'm giving the hackers a lot of clues
I mean,
can I store in my database all the string?
or
must I to store the hash and the (algorithm,cost,salt) in different places?
If somebody gets my DB he has all the hash passwords.
The security does not come from the information being secret. It comes from the algorithm being very computationally expensive.
The attack here is to guess a plaintext which, when hashed with the given algorithm and salt and cost, will result in the same hash value. Even with all the information given (except the plaintext obviously) and assuming a strong (random) plaintext password, it takes many many years, possibly millennia, to find one such value. And that's just for one password hash, to say nothing of a whole database of hashes.
The protection is in using an algorithm costly enough to make guessing infeasibly slow, not in keeping details of the algorithm (which salt and cost are) secret.
The purpose of salt is to make sure that hashes are uniquely generated and cannot be looked up in an existing database such as MD5 Decrypt. Even if a salt is leaked the attacker would have to break each hashed password individually.
can I store in my database all the string?
Yes, you may store it in the database as whole just like WordPress does.
If somebody gets my DB he has all the hash passwords.
Yes but as I mentioned the hashes are of no use unless the passwords are individually cracked using brute force and that would take an insane amount of computation cost.
Currently I'm just fooling around with PHP, but I came across an idea I want to expand on and need to know how secure it is in your opinion, and how I can improve it to make it acceptable for practical use.
This is how I store the passwords in the database:
plain text password -> hash password (I use whirlpool, but any method will practically work)->
shuffle/scramble the hashed password (with the str_shuffle() function).
I store the users password in the database like so, to make sure if the database is compromised, it would make it impossible for the attacker to reverse the broken password hash inside the database. (Because how can you reverse in a sense, random text that use to be a hash? - Although I'm sure you can create a list of possibilities by comparing a list of hashes that share the same chars.)
The way I check if the users password they entered on the login form is correct (compared to the broken hash in the database) is by counting the individual letters+numbers (a-f & 0-9) in both strings/passwords , and see if they match up, and if they do, I assume they're correctly logged in.
And again, I want to know how secure this is in your opinion, and how can I improve it to make it acceptable for practical use. (If possible.)
& I would also like to try my best to avoid a "reversible" hash. (i.e the idea of creating my own way of ensuring the passwords match, I want to make it more of an A best guess Assumption, to completely help ensure it will be impossible for an attacker to reverse the passwords in the database.
& Yes I know this is stupid because it most likely causes more security flaws rather then helps fix them. But this is just something I'm fooling around with, and maybe hope to make it practical.
OTHER INFO:
1) Passwords are stored with unique salts (so not 1 account shares the same salt)
2) Password salts are always changing (Each time a Successful Login happens with a users account, it will change the users salt in the database. I do this to change the hash in the datbase, causing a password collision to be less frequent (hopefully) & also to prevent unwanted users from using the same incorrect password multiple times to login (If they manage to come across one, only way to achieve this is by bruteforce or 'guessing' which any login system is vulnerable to).
When I say password collision, I mean the slightest chance that the word "hello" & "blue" share the same exact char count (as I explained, I count the individual chars + numbers, and compare them, to ASSUME its the correct password.)
3) I will also MAYBE keep the first 3chars/numbers of the hashed password unaffectedd by the str_shuffle, to also help ensure the passswords are correct. (By creating 2 checks, 1) check if both strings share the same FIRST 3 CHARS/Numbers & 2) Then compare the count of chars in each string. (Hoping to make password collisions, again, less frequent).
4) Obviously other security measures will be added (i.e max login attempts, captcha , etc.. to help protect against automated bruteforcing, to make it harder for a hacker to find a possible password or the real password.
I have made a successful PoC of this, and it works like a charm, although I have yet to test the PoC against a Dictionary Attack / Brute Force Attack, to see the chances of password collisions. & How frequent they are.
If I stated a lot of 'useless' information, ignore it. I'm just trying my best to explain this reasonably.
This seems terribly ineffective and insecure to me.
Most notably: Collisions. You mentioned that already in Other Info.
Just checking for the count of characters in the hashed & scrambled lets collision probability go through the roof. You enable one password to be also valid for all permutations of its hash. Considering the length of 128 characters in a whirlpool hash, this is a veeery large number.
So, basically, by allowing this, you allow a would-be bruteforcer to check many many thousand passwords at once, by entering a single one.
They will not gain permanent access to the system, since you said you alter the hash after each login, but the probability that they gain access ONCE is increased substantially.
Concerning the altered salt... how do you do that? I can't think of a way unless you apply the salt after hashing instead of before, which is not how a Salt works in hashing.
If you want to make it more secure then just use multiple hash iterations. Store the hashed password and the number of hash iterations. Every time the user logs in hash the hash again, store it, and increase the iteration count. This will change the stored hash sufficiently without introducing too many cryptographic weaknesses.
Your shuffling scheme will make the password less secure. Comparing the number of instances of letter and numbers after a shuffle increases the chance of two people having the same password value (collision, as you said).
The re-salting is something you could use. Each time the user successfully logs in, you can re-salt the password and save it again. This could be even better if you modified the PHP password procedure to use a hi-res time value, increasing the unique-ness. Essentially you're continuously rotating the salt of the password. You would have to save the clear password, compare its hash to the saved one, re-salt and hash the clear password and save again.
The output of a cryptographically strong hashing function is for all intents and purposes already pseudo-random. Attempting to add entropy by scrambling it does nothing. It does nothing to make the hash less "reversible", since the only way to "reverse" a hash is by choosing an input, hashing it, comparing it with the hash; that's the same thing you have to do when logging the user in, it's the same thing an attacker has to do, changing the comparison algorithm does not change this basic operation. (As others have pointed out, your weakened comparison algorithm actually aids an attacker.)
The accepted way to deal with this problem is already sufficient:
Make sure your input is unique by salting it with (pseudo) random noise, this forces an attacker to do actual brute force hashing.
Choose a hash that is slow (preferably bcrypt or scrypt, with a high enough cost factor that makes it feasible for you to do once, but infeasible for an attacker to do billions of times), this makes it computationally infeasible for an attacker to brute force a hash in his life time.
If both steps are done correctly, it's already infeasible to "reverse" a hash. No additional mind games needed.
Don't fiddle around with your idea any longer. It is insecure.
There are only about two ways for password security that provide a sufficient level of resistance against tampering:
Use a hardware security module executing something like HMAC-SHA1. The module is external hardware, the outside world does not know the internal secret (only available by physical access to the module) inside the module, and without that module the generated hashes will never be reconstructed. Being dedicated hardware with a "fast" hashing algorithm makes this a viable solution for lot's of password checks. See http://en.wikipedia.org/wiki/Hash-based_message_authentication_code for details.
Use very slow hashing algorithm. Things like "scrypt" or "bcrypt" will execute very slowly, thus hindering the fast bruteforce scan of list of passwords against a list of known hashes. PHP only has support for "bcrypt" at this time.
You may wonder why you should use external hardware encapsulating a secret. Simple: Anything that is accessible from the machine that is doing the hash can be stolen. Stealing the secret is like using the same salt (or none at all) for all keys: You end up "only" having a very fast hash algorithm with every other component known, and can start bruteforcing passwords right away.
So if there is no dedicated hardware, the only other option is a slow password hash algorithm.
There is a solution for PHP: password_compat is a library that reimplements the PHP password hash API for versions before PHP 5.5. If you are already using 5.5, you simply use these functions.
So recently I have been doing tons of research on how to secure passwords. I believe I understand the basics of it. As such I am attempting to write my own function to secure a password in php.
But I am somewhat confused when it comes to salting a password. We create a random unique salt and append it to a password and then hash it, and finally store the unhashed salt and hashed password/salt combination together in the database. This increases the search space of the hacker if he obtains access to the database and our hashed passwords.
So this seems like complete overkill of security, but everywhere I see the salt is always appended to the front or back of the password anyways. So looking at a SINGLE user's password this unique salt doesn't affect the search space does it? Although since each user has a unique salt the overall search space of EVERY user is dramatically increased.
Wouldn't it be more secure to create an algorithm that inserts the salt to a predictable, semi-random place in the password such as the length of the username/2? For example here is the steps of my proposed securing function:
Create a random salt
take username length %(mod) password length
insert the salt at the spot determined
hash
Example run:
random salt = 12345
len("imauserwithalongname") % len("mypass") = 2
valueToHash = my12345pass
Now our cracker has no idea where to put the salt without seeing our php/source, which (correct me if I am wrong) is much harder to gain access to than the database.
Also I know security should depend on the security of the key not secrecy of the algorithm, however I see nothing wrong with adding layers based on it, as long as the entire system does not depend on secrecy of the algorithm.
EDIT: Would doing this dramatically increase the search space of a cracker?
And what if we placed the salt in a place that depended on the length of the password, would that not destroy the purpose of using dictionary attacks, even on a per user basis?
Inserting the salt in a different spot doesn't increase the search space. If you are using a random salt for each user, a hacker does not know what each salt is per user anyway. The knowledge of its position in the unhashed string doesn't matter.
Use bcrypt or PBKDF2. Both algorithms enforce a salt and number of cycles. If you're patient enough, PHP 5.5 will just let you do password_hash($password).
As such I am attempting to write my own function to secure a password
in php.
Woah woah, hold it right there.
There's a saying passed down from cryptographers to us mere mortals which has held true for many many years. The saying goes like this:
Do not invent your own crypto.
Say it out loud, then say it again.
I know you're only trying to secure your passwords, but I had to get that out of the way. There are lots and lots of tried and tested methods to do what you want to achieve.
I appreciate you've done some research, but the internet is full of terrible terrible information, so I'm going to point you towards some useful articles.
Check out ircmaxell's security related
blogs.
A nice short list.
Here's some keywords to help you.
Bcrypt
Scrypt (someone please unstrike this when PHP supports it)
Again a very short list.
To address your specific concern. Salts are not needed to be kept private, as you say they are designed to stop attackers precomputing tables of valid password/hash combinations. However if you use a weak hashing algorithm they lose their value very quickly.
Security through obscurity is not as great as it seems. If a hacker gains access to your DB, the odds are quite high that they will also gain access to your filesystem. If they gain access to your source your custom method of storing passwords is a moot point.
In summary, custom algorithm + weak hash = insecure.
Instead you want to use tried and tested key derivation functions / key strengthening algorithms.
These are designed to make the computer work really hard to generate the hash, and makes it very difficult for an attacker to brute force a password.
Bcrypt stores the salt next to the password, and is proven to be very secure. Secure enough in fact that it is currently the recommended way to hash passwords by security experts.
In PHP 5.5 a simple password hashing API has been introduced based on Bcrypt, and for versions under 5.5 there is a password hashing compatibility library that does exactly the same thing.
That should be enough for you.
I personally think you're overdoing it. The most efficient way to salt a hash would be to have a dynamic, record-specif one AND a static one stored in a read-only file on the system. This is a very efficient yet secure way of salting hashes.
I think you misunderstood the purpose of the salt. The salt does not increase the search space for an attacker, after all it is stored plaintext with the hash-value. The purpose of a salt is, that an attacker cannot build one single rainbowtable, and then retrieve all stored passwords.
If you would append the same salt to every password, then the attacker cannot simply use an existing precalculated rainbow-table from the internet, he has to build a new rainbow-table for exactly this salt (existing rainbow-tables will contain passwords like "horse", but not passwords like horse8ze*w398dhek3+qmxno0). Unfortunately this single rainbow-table can then be used to get all passwords.
So we use a unique salt for every password. An attacker would have to build a separate rainbow-table for each password now, but why should he continue with building the table, when he already found a match (?), he cannot reuse the table later for other passwords. In other words, brute-force is faster than building a rainbow-table, so we made rainbow-tables useless.
So the salt should be unique for each password and if possible it should be unpredictable. Those criterias are difficult to fulfill with a deterministic computer, the best you can do is, to use the random source of the operating system to build the salts. Good hash algorithms for passwords like BCrypt and PBKDF2 repeat the hashing to become slow, and combine password and original salt in each iteration. It is not just a concatenation of password + salt.
Your idea about putting the salt somewhere secret does add a secret (where is the salt?), that will work as long as the attacker doesnt know your code. Getting the database (SQL-injection) is indeed easier than gaining access to the code, but the same goal can be achieved much easier with a pepper.
I tried to sum up this in a tutorial, maybe you want to have a look at it.
I'm looking at some code that I have not written myself. The code tries to hash a password with SHA512 and uses just time() as the salt. Is time() too simple a salt for this or is this code safe?
Thanks for the answers and comments. I will sum it up here for the new readers:
salt should be different for each user, so if 2 users register at the same time, their salts won't be unique. This is a problem, but not a big one.
but salt shouldn't be in any way related to the user, so time() is not a good salt.
"Use a random, evenly distributed, high entropy salt." -- That's a mouthful, so what code could possibly generate a random, evenly distributed, high entropy salt?
Ok, so how about I replace time() with a random string 32 char long. The random string could be generated from looping 32 times over a set of alphabet chars. Does that sound good?
Short answer:
No, time() is not a good salt.
Long answer:
copied from my answer to Salt Generation and open source software
What is a salt?
A salt is a random set of bytes of a fixed length that is added to the input of a hash algorithm.
Why is salting (or seeding) a hash useful?
Adding a random salt to a hash ensures that the same password will produce many different hashes. The salt is usually stored in the database, together with the result of the hash function.
Salting a hash is good for a number of reasons:
Salting greatly increases the difficulty/cost of precomputated attacks (including rainbow tables)
Salting makes sure that the same password does not result in the same hash.
This makes sure you cannot determine if two users have the same password. And, even more important, you cannot determine if the same person uses the same password across different systems.
Salting increases the complexity of passwords, thereby greatly decreasing the effectiveness of both Dictionary- and Birthday attacks. (This is only true if the salt is stored separate from the hash).
Proper salting greatly increases the storage need for precomputation attacks, up to the point where they are no longer practical. (8 character case-sensitive alpha-numeric passwords with 16 bit salt, hashed to a 128 bit value, would take up just under 200 exabytes without rainbow reduction).
There is no need for the salt to be secret.
A salt is not a secret key, instead a salt 'works' by making the hash function specific to each instance. With salted hash, there is not one hash function, but one for every possible salt value. This prevent the attacker from attacking N hashed passwords for less than N times the cost of attacking one password. This is the point of the salt.
A "secret salt" is not a salt, it is called a "key", and it means that you are no longer computing a hash, but a Message Authentication Code (MAC). Computing MAC is tricky business (much trickier than simply slapping together a key and a value into a hash function) and it is a very different subject altogether.
The salt must be random for every instance in which it is used. This ensures that an attacker has to attack every salted hash separately.
If you rely on your salt (or salting algorithm) being secret, you enter the realms of Security Through Obscurity (won't work). Most probably, you do not get additional security from the salt secrecy; you just get the warm fuzzy feeling of security. So instead of making your system more secure, it just distracts you from reality.
So, why does the salt have to be random?
Technically, the salt should be unique. The point of the salt is to be distinct for each hashed password. This is meant worldwide. Since there is no central organization which distributes unique salts on demand, we have to rely on the next best thing, which is random selection with an unpredictable random generator, preferably within a salt space large enough to make collisions improbable (two instances using the same salt value).
It is tempting to try to derive a salt from some data which is "presumably unique", such as the user ID, but such schemes often fail due to some nasty details:
If you use for example the user ID, some bad guys, attacking distinct systems, may just pool their resources and create precomputed tables for user IDs 1 to 50. A user ID is unique system-wide but not worldwide.
The same applies to the username: there is one "root" per Unix system, but there are many roots in the world. A rainbow table for "root" would be worth the effort, since it could be applied to millions of systems. Worse yet, there are also many "bob" out there, and many do not have sysadmin training: their passwords could be quite weak.
Uniqueness is also temporal. Sometimes, users change their password. For each new password, a new salt must be selected. Otherwise, an attacker obtained the hash of the old password and the hash of the new could try to attack both simultaneously.
Using a random salt obtained from a cryptographically secure, unpredictable PRNG may be some kind of overkill, but at least it provably protects you against all those hazards. It's not about preventing the attacker from knowing what an individual salt is, it's about not giving them the big, fat target that will be used on a substantial number of potential targets. Random selection makes the targets as thin as is practical.
In conclusion:
Use a random, evenly distributed, high entropy salt. Use a new salt whenever you create a new password or change a password. Store the salt along with the hashed password. Favor big salts (at least 10 bytes, preferably 16 or more).
A salt does not turn a bad password into a good password. It just makes sure that the attacker will at least pay the dictionary attack price for each bad password he breaks.
Usefull sources:
stackoverflow.com: Non-random salt for password hashes
Bruce Schneier: Practical Cryptography (book)
Matasano Security: Enough with the Rainbow Tables
usenix.org: Unix crypt used salt since 1976
owasp.org: Why add salt
openwall.com: Salts
Disclaimer:
I'm not a security expert. (Although this answer was reviewed by Thomas Pornin)
If any of the security professionals out there find something wrong, please do comment or edit this wiki answer.
As for what seems to be a good source for your random salt
Also read: What is the most secure seed for random number generation?
In the absence of dedicated, hardware based, random generators, the best way of obtaining random data is to ask the operating system (on Linux, this is called /dev/random or /dev/urandom [both have advantages and problems, choose your poison]; on Windows, call CryptGenRandom())
If for some reason you do not have access to the above mentioned sources of random, in PHP you could use the following function:
From the source of phpass v0.3
<?php
/**
* Generate pseudo random bits
* #copyright: public domain
* #link http://www.openwall.com/phpass/
* #param int $length number of bits to generate
* #return string A string with the hexadecimal number
* #note don't try to improve this, you will likely just ruin it
*/
function random_bits($entropy) {
$entropy /= 8;
$state = uniqid();
$str = '';
for ($i = 0; $i < $entropy; $i += 16) {
$state = md5(microtime().$state);
$str .= md5($state, true);
}
$str = unpack('H*', substr($str, 0, $entropy));
// for some weird reason, on some machines 32 bits binary data comes out as 65! hex characters!?
// so, added the substr
return substr(str_pad($str[1], $entropy*2, '0'), 0, $entropy*2);
}
?>
Updated
It's not a really good salt, but probably good enough to defeat all but the most determined and resourceful attackers. The requirements for a good salt are:
Different for each user
long enough (at the very least alphanumeric 8 characters) to make the concatenation of salt and (potentially weak) password too long for a brute force attack.
time() values are not really long enough, since they have 10 characters, but only digits.
Also, sometimes two users may get the same value when they are created within the same second. But that's only a problem if you have situations where many users are automatically created within the same second.
In any case, far more important than a perfect salt is using a good hash function, and SHA512 is one of the best we have available right now.
This post may veer a little too far away from your original question, but I hope you find it useful;
Security is about raising barriers and hurdles; defence in depth. There is no truly secure hashing solution, just ones that are hard to break. It's like putting in a burglar alarm and window locks in your house - make your site less attractive to break into than someone else's.
Salt for a crypt algorithm is only a small part of the security problem. A single salt simply means that there is one less thing to figure out when trying to break the password for multiple users. A low-entropy salt (such as the server's time) makes it a little bit harder, and a high-entropy salt makes it harder still. Which of these to use, and whether it's something you need to worry about primarily depends upon both the sensitivity of the data you're protecting, but also what other security measures you have in place. A site that just gives a personalised weather forecast for a selected city obviously has less sensitive data than one which has your home address, mother's maiden name, date of birth and other info which could be used for identification purposes.
So here's the rub; a high entropy salt is still a bad salt if it's easily obtainable.
In the real world, storing a salt in the database (random or not) is probably less secure than using a constant salt and burying it away from private eyes in a file inaccessible via the web browser. Whilst a unique and high entropy salt is harder to guess, if you've allowed root login from any server on MySql and set the password to 'password' it doesn't really matter! Constrast how easy it is to crack the database versus getting a valid login to your server - which is possibly more difficult to do discretely as you can put fail2ban and a plethora of other attack vector watchers in place depending upon your setup.
You can combine the two approaches by storing the location of a file containing a user-specific salt in the database, rather than the salt itself. Whether having to crack both the file system and the database is warranted depends whether the sensitivity of the data you are trying to protect warrants this overhead.
Another, alternative, recommendation from security experts is to store the username in a separate database (and ideally different technology) to the password, and reference between the two using a UUID. E.g. use both MySQL and SQLite. This means that both databases have to be cracked (and is also why, to go down a separate rabbit hole for the sake of an example, you should not store user details and credit card numbers in the same database since one is of no use without the other).
Note that Algorithms like SHA-512 and Blowfish can return the salt as part of their hash. Be careful with these as if you store the complete hash you give away the algorithm, which means there's two less thing for the hackers to figure out (the salt also gives away the algorithm).
Make sure you enforce strong passwords and usernames, so dictionary attacks will fail; I know of dictionaries for all 6-alphanumeric combinations of username/ password entries for MD5 and I suspect that there are more than this available for all sorts of algorithms. With the explosion of low-cost cloud and CPGPU computing, the size and complexity of available dictionaries is going to explode.
Ultimately, the most secure way is never to programatically generate a salt but require a user to enter it along with their username and password over a SSL link (so can't be snooped), but never store it. This is the approach taken by credit card companies; i.e. the 3-digit CSV security key on your credit card which you have to enter each and every time you buy online, since it should never be stored in any database. If you really want to generate the salt, send it to them separately (e.g. via SMS message or Email) and still make them enter it manually each time. With this approach, although more secure, you need to contrast the complexity against whether users will just stop using the site as you've made it too difficult for them to be bothered with it.
All of the above still relies on the fact that you also have protection in place against session hijacking, cross-site scripting, etc., etc. The world's strongest password algorithm is irrelevant if all I need to do is to calculate a valid PHPSESSID for a logged-in user and hijack it!
I am not a security expert, but have read up on this as much as I reasonably can do. The fact that there are so many books on the subject indicates how big the answer to your question really is.
A couple of really great books you might like to try which I've found invaluable are;
Web Application Vulnerabilities Detect, Exploit, Prevent - ISBN-13: 978-1-59749-209-6
Preventing Web Attacks with Apache - ISBN-13: 978-0-321-32128-2
No, time() is not a good salt
It's best not to reinvent the wheel when it comes to authentication, but to answer your question, no. The problem with time():
It's predictable and it correlates to potentially discoverable things. These issues make it easier to cross-match different hashed results.
There aren't very many possible values. Since the high-order bits don't change, it's an even narrower salt than it first appears.
Using it repeats previous mistakes. If this app were the first one to use time() as a salt, at least it would require a new attack.
Yes.
It seems that a unix timestamp, stored in the user database as a "Member since" field going to be decent salt.
However, salt question is most negligible one.
There are much more important things you have to pay attention to:
Most likely not a password nor salt or hashing algorithm going to be weakest part of your site. Some lame file injection or XSS or CSRF surely is. So, don't make a too big deal of it.
Speaking of a true random string of 32 char long in the typical web-application is like speaking about 32-inch armored door in the wooden barn.
Speaking of passwords, most ever important thing is password complexity. With weak password no salt nor hashing algorithm, even super-ingenious-incredible-hard one, could help. It's a pain to ask users to use complex password, but without it everything else becomes a piece of crap.
So, your first concern should be password complexity. 12-16 characters of different case, including numbers and punctuation is a requirement.
As for the salt, I see no benefit in using time, as you have to store it along with other user data. Better use a email - it's random enough and you have it already anyway. Don't forget to rehash a password if user changes their email. it seems that unix timstamp going to be a decent salt, no need to use email or anything else.
Update
As I can see, many people still unable to get the point.
Like that guy from the comments, saying
Many users use weak passwords (we should educate them, or at least keep trying), but that is no excuse; they still deserve good security
They deserve, no doubt. But with weak password the mission. is. impossible.
If your password is weak, then no salt will protect it.
While salt is not that important to spend a 10-kilobyte text on the topic.
Salt is use to prevent rainbow attacks by breaking the match between the password and precomputed hash. So the main task for a salt is to be different for each user/password record. Quality of randomization of the salt doesn't matter much as long as the salt is different for different users.
the date when a member joins a forum/website is generally openly access able , which would be same as time() hence making your salt useless.
No! Never use the current time as the salt. You can use something like 'SecureRandom' in java to generate a random salt that is secure. Always use an unpredictable random number as the salt. Using time as the salt will help you to remove collisions only upto a certain extent(because two users can sypply the same passwords at the same time), but still make the passwords recoverable.
The user name should be sufficient enough and perhaps the registration time stamp, but you should store it somewhere in the database. Anyway every value you use to salt your password hash, should be stored some way, so you can recalculate the hash.
Is salting with user name + a time stamp secure enough? It should be. For cracking SHA512 Hashes normally Rainbow Tables are used. A user name + a time stamp should be a salt which is uniquq enough, so there is no way there is some Rainbow Table on the net which contains precalculated hashes with passwords, which are salted this way.
I was reading this tutorial for a simple PHP login system.
In the end it recommends that you should encrypt your password using md5().
Though I know this is a beginners' tutorial, and you shouldn't put bank statements behind this login system, this got me thinking about encryption.
So I went ahead and went to (one of the most useful questions this site has for newbies): What should a developer know before building a public web site?
There it says (under security) you should:
Encrypt Hash and salt passwords rather
than storing them plain-text.
It doesn't say much more about it, no references.
So I went ahead and tried it myself:
$pass = "Trufa";
$enc = md5($pass);
echo $enc; #will echo 06cb51ce0a9893ec1d2dce07ba5ba710
And this is what got me thinking, that although I know md5() might not the strongest way to encrypt, anything that always produces the same result can be reverse engineered.
So what is the sense of encrypting something with md5() or any other method?
If a hacker gets to a password encrypted with md5(), he would just use this page!.
So now the actual questions:
How does password encryption work?
I know I have not discovered a huge web vulnerability here! :) I just want to understand the logic behind password encryption.
I'm sure I'm understanding something wrong, and would appreciate if you could help me set my though and other's (I hope) straight.
How would you have to apply password encryption so that it is actually useful?
What about this idea?
As I said, I may/am getting the whole idea wrong, but, would this method add any security in security to a real environment?
$reenc = array(
"h38an",
"n28nu",
"fw08d"
);
$pass = "Trufa";
$enc = chunk_split(md5($pass),5,$reenc[mt_rand(0,count($reenc)-1)]);
echo $enc;
As you see, I randomly added arbitrary strings ($reenc = array()) to my md5() password "making it unique". This of course is just a silly example.
I may be wrong but unless you "seed the encryption yourself" it will always be easily reversible.
The above would be my idea of "password protecting" and encrypted password, If a hacker gets to it he wont be able to decrypt it unless he gets access to the raw .php
I know this might not even make sense, but I can't figure out why this is a bad idea!
I hope I've made myself clear enough, but this is a very long question so, please ask for any clarification needed!
Thanks in advance!!
You should have an encryption like md5 or sha512. You should also have two different salts, a static salt (written by you) and then also a unique salt for that specific password.
Some sample code (e.g. registration.php):
$unique_salt = hash('md5', microtime());
$password = hash('md5', $_POST['password'].'raNdoMStAticSaltHere'.$unique_salt);
Now you have a static salt, which is valid for all your passwords, that is stored in the .php file. Then, at registration execution, you generate a unique hash for that specific password.
This all ends up with: two passwords that are spelled exactly the same, will have two different hashes. The unique hash is stored in the database along with the current id. If someone grab the database, they will have every single unique salt for every specific password. But what they don't have is your static salt, which make things a lot harder for every "hacker" out there.
This is how you check the validity of your password on login.php for example:
$user = //random username;
$querysalt = mysql_query("SELECT salt FROM password WHERE username='$user'");
while($salt = mysql_fetch_array($querysalt)) {
$password = hash('md5',
$_POST['userpassword'].'raNdoMStAticSaltHere'.$salt[salt]);
}
This is what I've used in the past. It's very powerful and secure. Myself prefer the sha512 encryption. It's actually just to put that inside the hash function instead of md5 in my example.
If you wanna be even more secure, you can store the unique salt in a completely different database.
Firstly, "hashing" (using a cryptographic one way function) is not "encrypting". In encryption, you can reverse the process (decryption). In hashing, there is (theoretically) no feasible way of reversing the process.
A hash is some function f such that v cannot be determined from f(v) easily.
The point of using hashing for authentication is that you (or someone seeing the hash value) do not have any feasible way (again, theoretically) of knowing the password. However, you can still verify that the user knows his password. (Basically, the user proves that he knows v such that f(v) is the stored hash).
The weakness of simply hashing (aside from weak hash functions) is that people can compile tables of passwords and their corresponding hash and use them to (effectively) get the inverse of the hash function. Salting prevents this because then a part of the input value to the hash is controlled and so tables have to be compiled for that particular salt.
So practically, you store a salt and a hash value, and authenticate by hashing a combination of the salt and the password and comparing that with your hash value.
MD5 is a one way hashing function which will guard your original password more or less safely.
So, let's say your password is "Trufa", and its hashed version is 06cb51ce0a9893ec1d2dce07ba5ba710.
For example, when you sign in to a new webpage, they ask you for your username and password. When you write "Trufa" as your password, the value 06cb51ce0a9893ec1d2dce07ba5ba710 is stored in the database because it is hashed.
The next time you log in, and you write "Trufa", the hashed value will be compared to the one in the database. If they are the same, you are authenticated! Providing you entered the right username, of course.
If your password wasn't stored in its hashed form in database, some malicious person might run a query somehow on that database and see all real passwords. And that would be compromising.
Also, since MD5 is a 128 bit cryptographic function, there are 2^128-1 = 340282366920938463463374607431768211455 possible combinations.
Since there are more possible strings than this, it is possible that 2 strings will generate the same hash value. This is called a collision. And it makes sure that a hashed password cannot be uniquely reverse engineered.
The only vulnerability with salting is that you need to know what the salt is in order to reconstruct the hash for testing the password. This is gotten around by storing the entry in the authdb in the form <algorithm>$<salt>$<hash>. This way the authdb entry can be used by any code that has access to it.
You're missing the important step - the salt. This is a unique (per user, ideally) bit of extra data that you add to the password before hashing it.
http://en.wikipedia.org/wiki/Salt_%28cryptography%29
Your idea (salting) is well known and is actually well-implemented in the PHP language. If you use the crypt() function it allows you to specify a string to hash, a method to encrypt (in some cases), and a salt. For example,
$x = crypt('insecure_password', $salt);
Returns a hashed and salted password ready for storage. Passwords get cracked the same way that we check if they're right: we check the hash of what the user inputs against the hash of their password in the database. If they match, they're authenticated (AFAIK this is the most common way to do this, if not the only). Insecure passwords (like password) that use dictionary words can be cracked by comparing their hash to hashes of common passwords. Secure passwords cannot be cracked this way, but can still be cracked. Adding a salt to the password makes it much more difficult to crack: since the hacker most likely doesn't know what the salt is, his dictionary attack won't work.
For a decent hash the attacker won't be reversing the hash, they'll be using a rainbow table, which is essentially a brute-force method made useful if everyone uses the same hash function.
The idea of a rainbow table is that since hashing is fast I can hash every possible value you could use as a password, store the result, and have a map of which hash connects to which password. If everyone just takes their passwords and hashes them with MD5 then my hash table is good for any set of password hashes I can get my hands on!
This is where salting comes in. If I take the password the user enters and add some data which is different for every user, then that list of pre-determined hashes is useless since the hash is of both the password and some random data. The data for the salt could be stored right beside the password and even if I get both it doesn't help me get the password back since I still have to essentially brute force the hash separately for every single user - I can't form a single rainbow table to attack all the hashes at once.
Of course, ideally an attacker won't get the list of hashed passwords in the first place, but some employees will have access so it's not possible to secure the password database entirely.
In addition to providing salt (or seed), the md5 is a complex hashing algorithm which uses mathematical rules to produce a result that is specifically not reversable because of the mathematical changes and dataloss in throughput.
http://en.wikipedia.org/wiki/Cryptographic_hash_function
md5 (or better put: hash algorithms in general) are used to safely store passwords in database. The most important thing to know about hashes is: Hashes are not encryptions per se. (they are one-way-encryptions at most). If you encrypt something, you can get the data back with the key you used. A hash generates a fixed-length value from an arbitrary input (like a string), which can be used to see if the same input was used.
Hashes are used to store sensitive, repeatly entered data in a storage device. Doing this, nobody can recreate the original input from the hash data, but you can hash an incoming password and compare it to the value in the database, and see if both are the same, if so, the password was correct.
You already pointed out, that there possibilites to break the algorithm, either by using a database of value/hash pairs or producing collisions (different values resulting in the hash value). You can obscure this a bit by using a salt, thus modifying the algorithm. But if the salt is known, it can be used to break the algorithm again.
I like this question. But I think you've really answered yourself.
The site you referenced uses dictionary lookups of known, unsalted, md5's - it doesn't "crack" anything.
Your example is almost good, except your application needs to be able to regenerate the md5 using the same salt every time.
Your example appears to use one of the random salts, which will fail 2 of 3 times if you try to compare a users password hash to something input.
People will tell you to also use SHA1 or SHA256 to be have a 'stronger' hash - but people will also argue that they're all 'broken.'
That documentation is misleading -- it teaches a "vulnerable" concept and presents it as somehow being "secure" because it (the saved password) looks like gibberish. Just internet junk that won't die. The following link should clear things up (you have already found a good bit of it though, it seems. Good work.)
Enough With The Rainbow Tables: What You Need To Know About Secure Password Schemes talks about MD5 (and why it should not be used) along with salt (e.g. how to thwart rainbow attacks) as well as provides useful insights (such as "Use someone else’s password system. Don’t build your own"). It is a fairly good overview.
This is my question about the aspects of md5 collision, slightly related to your question:
Is there any difference between md5 and sha1 in this situation?
The important part is in the first 3 rows, that is: you must put your salt before the password, if you want to achieve stronger protection, not after.
To simply answer the title of your question, md5's only real use nowadays is for hashing large strings (such as files) to produce checksums. These are typically used to see if both strings are identical (in terms of files, checksums are frequently used for security purposes to ensure a file being distributed hasn't been tampered with, for example).
To address each of your inline questions:
How does password encryption work?
How would you have to apply password encryption so that it is actually useful?
Secure password hashing works by taking the password in plain text form, and then applying a costly hashing function to it, salted with a cryptographically secure random salt to it. See the Secure hash and salt for PHP passwords question for more detail on this.
What about this idea?
Password hashing does not need to be complicated like that, and nor should it be. Avoid thinking up your own algorithms and stick with the tried and tested hashing algorithms already out there. As the question linked above mentions, md5() for password hashing has been obsolete for many years now, and so it should be avoided.
Your method of generating a "random" salt from an array of three different salts is not the randomness you're looking for. You need unique randomness that is suitable for cryptographically secure (i.e. using a cryptically secure pseudo-random number generator (CSPRNG)). If you're using PHP 7 and above, then the random_bytes function can be used to generate a cryptographically secure salt (for PHP 5 users, the random_compat library can be used).