I've been studying/looking about on Google for TOO long and although I find many so-so tutorials, I'm wondering a bit about the "optional SALT" parameter in the (crypt) function within PHP. I have too many tabs open and getting nowhere so, at this point, I figured id just ask for help.
As far as the salt, I read somewhere that if you don't add it, it will be added for you but that this is not good practice. I can't seem to find the "why" it's good/not good. How should this be handled?
I've read a few things here and there about randomizing salts but others say it doesn't matter...again, confusing.
Also I'm having problems checking against the stored data as well. Obviously if I do something like
crypt("pass string here",salt here);
ill get a random string for the pass....so on a user log in, then the value of
$_POST['the entered name/pass etc '];
and checking against the db value for that users pass would always equal to false. So then I suppose that id have to rehash /salt the pass given upon user entry and then test against what's on the db?
Also, I've read throughout the net (but at this point I'm confused) that somehow the salt is stored in the db? and it doesn't have to be hidden?
I can keep going on and on, just lost honestly, I think I've read too much and not sure how to proceed. At this point, What id REALLY prefer is a GOOD link with tutorial if anyone has those resources.
You need to generate a secure random salt value when the user signs up, and store that salt in the database.
When the user logs in, fetch the salt and hash from the database, compute the hash of the password they typed using the original salt, and make sure the hash matches.
Also, don't use general-purpose hash algorithms (such as MD5 or SHA*); instead, use dedicated slow password-hashing algorithms, such as bcrypt or scrypt or PBKDFv2.
To maximize security, you never have a plaintext password in the database and leave it open to anyone who has/can get access to that database. So what you do is pick a predefined salt, take the user's desired password and encrypt it using the salt and a hash.
The salt is some extra random characters you add on to make the hashed password even more secure., you should keep track of this.
The hash then takes the salt + password and generates a random string based on it, such that you will always get that unique hash if you give it the same salt+password.
This seems like a fairly useful introduction to salting/hashing:
http://crackstation.net/hashing-security.htm
Related
I am trying to get a better understanding on Hashing and Encryption, however I stumbled upon questions that I can't seem to find in Google because Google keep offering basic difference of Hashing and Encryption, which I already read.
More over a lot of people ask in StackOverflow which have no idea about the difference between encryption and hashing gets to the top of the SO's search engine. Which doesn't answer my questions, and didn't help me. So I wanted to make sure a few things about hashing a password and encrypting one.
Now let's say I wanted to secure a new registered user..
I need to filter it first. (Skipped because of unrelated)
After I get a 'safe' form of the password, I hash it.
$safePassword; // Already filled with safe password.
$hash = password_hash($safePassword,PASSWORD_ARGON2I);
Then insert it to database.
Now this is the where questions rises.
Do I still need to encrypt the hashed password?
If so, how do I securely encrypt the password? (I'm going to use AES)
AES_ENCRYPT(str, key_str);
Where str is the String that we wanted to encrypt and key_str is the encryption key.
Another question rises
How do I keep the key_str safe, so I can use it for further use (for authentication)?
You don't need to encrypt the password, just running it through your password hash, like you included in your question, is perfectly fine. Hashing is a one-way operation, so it is "impossible" to reverse the hash and get the original password.
Encrypting passwords after hashing them doesn't make things any less secure, it just doesn't really make things any more secure either. It also introduces more problems - where to keep the key?
Stick to just Argon2, anything further is unnecessary.
Now let's say I wanted to secure a new registered user..
I need to filter it first. (Skipped because of unrelated)
If by "filter", you mean somehow altering this password.... no! Not only do you not need to do this, you're actually causing yourself a real headache later on down the road, and reducing the security of the password.
Now this is the where questions rises.
Do I still need to encrypt the hashed password?
No. Hashing is a one-way function. You cannot recover the password from its hash. (You could use a rainbow table, which is effectively a list of passwords that result in certain hashes. That's what a proper salt helps prevent.)
There is nothing gained by encrypting this hash.
Another question rises
How do I keep the key_str safe, so I can use it for further use (for authentication)?
This is actually a key reason the encryption isn't useful. To use it, you would need to decrypt it, which means keeping the keys around in the same place as the hash data in the first place.
So let's say I have "site1.mysite.com", "site2.mysite.com", etc. I want people (developers) to access some of the data via PHP generated JSON, but I also don't want to have to set up user accounts, sign ins, blah blah blah.
I don't want it to be open for "everybody".
What I started doing was this:
Users need to add "&user=somethingigivethem" and "key=somethingelseigivethem". These are values I provide to the user.
The key is currently the MD5 hash of the "user" and something like "53CR37P$%%" so basically:
$key_validator = md5($_GET['user'].'53CR37P$%%');
if($_GET['key'] === $key_validator){
//show JSON
} else {
//show error
}
Are there any major flaws in doing it this way?
So basically, if Joe Developer wants access, you give him a username and a key (which is an MD5 hash of his name + your salt). Joe can then make requests to your data.
If Joe wants to (ie. takes the time) he can probably figure out your hashing scheme just by trying different combinations of his username & salt values. And once he does, he'll know your salt and can access any other user's data.
I guess the question is: how valuable is this data? If you don't really care if other people get access and you really just want to keep out people who aren't too motivated to get your data, then this will work.
You could always combine an md5 and sha1 values with a randomized salt and also include your original salt value.
Example:
$key_validator = md5(sha1($_GET['user'].rand(0,1000)).'53CR37P$%%');
A little bit harder to crack, but you get the picture.
If I understood well, you generate both user and key for the user.
So the user have not to register and not to create it's own combination.
Making a key based on the user may be predictable quite easily, and overall with MD5.
I would recommend 2 ways:
If you really do not want to use your own database, generate a password based on better encryption system so people cant peak around the seed and encryption formula
(after all, makeing a md5 with the seed inside is a sort of "having the key into the password itself", no good)
Better encryption system supported by php: mainly all :) (you may need to install mcrypt extension) (support tens of encryptions, including most current like DES, 3DES, CAST, 2FISH, etc)
If you have no problem in using a database (or why not, a local file having the username/password pairs) , just generate a random strong password and keep the pairs in your database, and then just check against your stored values to give access, you still dont ask to the user to "register"
Oh, and don't forget, MD5 is only one way encryption, while real encryption with 3DES etc is reversible, so you can also compare things against real value.
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.
Is there any benefit to using:
sha1($long_unpredictable_randomly_generated_salt.$password.$global_salt)
over
sha1(sha1($username).$password.$global_salt)
The unique salt is obviously stored in the database, while the global salt is in a configuration file on the server.
I know the purpsoe of a salt is just to be unique, and prevent pre-calculated hash tables.. so I see no reason the long hash generated by sha1($username) is not good enough.. but as security is very important, I thought i'd ask for informative advice here from somebody who may know better :-)
The disadvantage is that the username is mostly known, so when someone knows this 'formula' you made up, he can just calculate sha1(user_to_hack) and this part won't have any additional benefit. In fact, it won't matter much if you use sha1(username) or just username in this case.
In the other case, you're using a value that is not exposed, so even when someone knows your formula (which everybody knows now), he'll still needs the value of that unique salt too before it's any use to them, so they'll need to get to your database. I assume you're making up a unique salt for each user?
You'll probably need to get data anyway, so the unique salt is probably faster too, because you won't need to calculate the hash over username.
But anyway, both are pretty safe, but only if you implement the actual login procedure well. I wouldn't worry about which one to use right now.
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).