Is using MD5 the safest way to encrypt passwords in PHP?

Asked

Viewed 22,208 times

19

I know there are several methods of encrypting passwords in PHP (md5, sha1, Base64...) although I don’t know much about, what I see most is the use of MD5.

Using MD5 to encrypt passwords is the safest way? If not, which one to use?

  • 5

    It’s not, check out http://answall.com/a/2405/21328.

  • 1

    It’s very complicated to say "the safest" that doesn’t exist. Always try to use passwords in Hash format (nonreversible encryption) a good technique is called "hash-salt" which consists of "salting a hash" that is, besides the password add other information that only the programmer knows, for example. when saving the password in the database, add other data such as email size, password size, etc.. password = password + email + sizeNew, this way is more difficult an attack by brute force.. brute force (trial and error) is the only way to break a password in hash format.

  • 3

    @Alexandrepreviatti In fact, "adding other information that only the programmer knows" is called "pepper", not "salt" (i.e. it is a type of key, but of not so critical importance). A salt just needs to be unique, it doesn’t even need to be secret. The ideal is that it is random (but your suggestion to use the email is not at all bad - except that if the user changes his password, then changes back to the previous password, the result of the hash will be the same, and this is not good).

  • 1

    Hello Vinicius. Base64 is not encryption. Although the use of this algorithm makes any text unreadable to a person, the transformation of Base64 is simple and does not require a key, so the information is not actually hidden.

7 answers

19


There is a very secure and native PHP solution that is the password API (password API). It is available from version 5.5 natively, but can be used from version 5.3 with a lib available on Github, call Password Compat.

The advantages of using such an API is that it is simple and extremely secure. See the output example for teste with the mechanisms of hash most commonly used (md5 and sha...):

MD5

for ($i = 0; $i < 5; $i++) {
    md5('teste');
}

/* Iterações
    1 - 698dc19d489c4e4db73e28a713eab07b
    2 - 698dc19d489c4e4db73e28a713eab07b
    3 - 698dc19d489c4e4db73e28a713eab07b
    4 - 698dc19d489c4e4db73e28a713eab07b
    5 - 698dc19d489c4e4db73e28a713eab07b

    Resultado: Sempre a mesma string
*/

SHA1

for ($i = 0; $i < 5; $i++) {
    sha1('teste');
}

/* Iterações
    1 - 2e6f9b0d5885b6010f9167787445617f553a735f
    2 - 2e6f9b0d5885b6010f9167787445617f553a735f
    3 - 2e6f9b0d5885b6010f9167787445617f553a735f
    4 - 2e6f9b0d5885b6010f9167787445617f553a735f
    5 - 2e6f9b0d5885b6010f9167787445617f553a735f

    Resultado: Sempre a mesma string
*/

SHA256

for ($i = 0; $i < 5; $i++) {
    hash('sha256', 'teste');
}

/* Iterações
    1 - 46070d4bf934fb0d4b06d9e2c46e346944e322444900a435d7d9a95e6d7435f5
    2 - 46070d4bf934fb0d4b06d9e2c46e346944e322444900a435d7d9a95e6d7435f5
    3 - 46070d4bf934fb0d4b06d9e2c46e346944e322444900a435d7d9a95e6d7435f5
    4 - 46070d4bf934fb0d4b06d9e2c46e346944e322444900a435d7d9a95e6d7435f5
    5 - 46070d4bf934fb0d4b06d9e2c46e346944e322444900a435d7d9a95e6d7435f5

    Resultado: Uma string complexa e grande mas ainda assim sempre a mesma string
*/

PASSWORD API

for ($i = 0; $i < 5; $i++) {
    password_hash('teste', PASSWORD_DEFAULT);
}

/* Iterações
    1 - $2y$10$zRlWkrqyTlEBsCVVf9KOvu3ADTEjOV.TiPHDu8efmgaPCQ75c2V7K
    2 - $2y$10$BydsqC30UGc3QmvalCFTt.pm22fg22195cav.lZOnfSNY9wL5ZcJe
    3 - $2y$10$XHpaG8blIsZCTNPXEubiz.2EyyyZktvydLDu1HtieBkpohN9vswQS
    4 - $2y$10$vNJabya/sj9MZd.DaEwtXuVwqpIwEOcBPN38gOh2gr2wanPwsQVSu
    5 - $2y$10$z3PB5TQHXgml3J0iDMhI8.HrM19Ce77YcI5sYfQQFU3a94.XBzQO.

    Resultado: a cada iteração uma nova hash gerada
*/

For validation the password_verify passing as first parameter the password provided by the user and as according to the hash which is in the database.

$hash1 = '$2y$10$zRlWkrqyTlEBsCVVf9KOvu3ADTEjOV.TiPHDu8efmgaPCQ75c2V7K';
var_dump(password_verify('teste', $hash1));
//true

$hash2 = '$2y$10$BydsqC30UGc3QmvalCFTt.pm22fg22195cav.lZOnfSNY9wL5ZcJe';
var_dump(password_verify('teste', $hash2));
//true

$hash3 = '$2y$10$XHpaG8blIsZCTNPXEubiz.2EyyyZktvydLDu1HtieBkpohN9vswQS';
var_dump(password_verify('teste', $hash3));
//true

$hash4 = '$2y$10$vNJabya/sj9MZd.DaEwtXuVwqpIwEOcBPN38gOh2gr2wanPwsQVSu';
var_dump(password_verify('teste', $hash4));
//true

$hash5 = '$2y$10$z3PB5TQHXgml3J0iDMhI8.HrM19Ce77YcI5sYfQQFU3a94.XBzQO.';
var_dump(password_verify('teste', $hash5));
//true

$hashDesconhecida = '$2y$10$z3PB5TQHXgml3J0iDMhI8.HrM19Ce77YcI5sYfQQFU3a94.X99999';
var_dump(password_verify('teste', $hashDesconhecida));
//false

There are other ways to apply hash in passwords, of course. Many frameworks have their own mechanisms, some quite safe, others a little less but compared to the methods presented here (md5, sha1, hash with sha256 and password API) to password API takes the best without a shadow of a doubt.

If you would like to check out these examples I have passed on: https://3v4l.org/mdFil

  • Thank you very much, you solved my problem on that. Now how can I add such "salty" without problems in password_hash(), remembering that in PHP 7.0.3 they talk about having forbidden something in the function

  • 1

    You can use salt in two ways: 1) a single salt for the application - must be stored in a settings file for example; 2) a single salt per user - must be stored in the database per user

  • 1

    I tested now and checked the following: even using a salt, to compare the password (password_verify), just provide only the string provided by the user and the hash in the database, salt is not necessary in the variance, only in the same creation.

  • In code how is salt? I’m sorry you ask, but it’s to make sure I’m not doing it wrong

  • @Vinicius, check out this example: https://3v4l.org/flgN3. Remember only that if you use version 7 of PHP salt is already deprecated.

  • 3

    @Vinicius the password API already uses a salt, you don’t need to add one yourself (by the way, the default hash of this API is bcrypt, which is considered safe enough to hasehar passwords). Andre, using "a single salt for the application" is useless, the salt function is to be unique to each user and for each password (i.e. if the user has changed the password, the salt has to change as well). But since in recent versions the API itself already does this for you, either... And at the time of checking, in fact it is not necessary to pass the salt again, because the output of the hash already includes the salt.

  • Excellent response!

Show 2 more comments

9

The answer is simply nay, MD5 is not the safest and was not near the first placed. :)

Hash != security

The first thing that needs to be demystified is that encryption or hash generation algorithms are not synonymous security, which is something much more comprehensive.

For example, it does no good all the security on the server if the communication with the client occurs by sending passwords to the URL or even if there is no use of HTTPS. Likewise, it is useless to hide the password well and leave the credit card numbers stored in plain text.

Risks of the MD5

It’s really hard to say that the MD5 is absolutely safe or unsafe. But compared to the other algorithms, he’s one of the less secure simply by being faster to calculate and thus making it a little easier to guess the password by brute force.

A article on hashing speed, 2012 contains a speed calculation to hash MD5 of all combinations of passwords using uppercase and lowercase letters, numbers and symbols. Part of the result was:

  • 6 characters: 47 seconds
  • 7 characters: 1 hour and 14 minutes
  • 8 characters: approximately 465 days

Consider that the hardware is outdated and that there are many possibilities to parallelize or simplify this work. Someone with a lot of will, willing to invest a little time and money, could easily decrease these 465 days to a few days or even hours.

Keep in mind even though the time above is the time total, So unless your password is a string of letters "z," it’s probably going to be found first. In addition, simple techniques like leaving the special characters for later can speed up even more. On this website only 17% of users used symbols.

We have to agree that eight-character passwords cannot be guilty of being insecure. In this case, the algorithm is. And this will put most of your customers at risk. Statistics collected by some websites show that most passwords have 8 digits or less.

On top of that, many of the implementations of MD5 use only "raw" lgoritmo, that is, they do not use any kind of "salt", which leaves open the use of hash dictionaries that already have the most common passwords.

Beyond the MD5

Getting back to the point, it may be that MD5 is sufficiently safe and collision-free for a simple case you have today. However, simple hash algorithms are usually not suitable for passwords and there is no reason why you should not use something better.

There are specific solutions to generate password hashes like bcrypt and PBKDF2 that enable you to adjust the level of security you want. They are iterative, that is, apply multiple encryption iterations according to the desired level.

Season the password

The advantage of the algorithms mentioned above is that they reinforce the use of salt (salt), which is very important to decrease the impact of attacks.

Salt must be a unique value per password that causes each of them to be generated in a unique way.

This greatly decreases the efficiency of brute force attacks in the sense that even equal passwords will have a different hash value.

Don’t invent the wheel, PHP is already round

PHP (from the 5.5) has the function password_hash that uses the algorithm bcrypt to encode passwords safely.

The following code, extracted from the documentation, illustrates how you can use the function:

echo password_hash("rasmuslerdorf", PASSWORD_BCRYPT)."\n";

Note that the function already creates a cryptographically safe salt. Do not forget that this value is included along with the hash to make it possible to verify the password later through the function password_verify.

Don’t be lazy, boy

In short, with a function already implementing what is recommended to hash passwords, there is no reason today to continue using something potentially more insecure.

  • 2

    Good answer, I only have two observations: 1) 8-character passwords [ASCII] only contain 56 bits of entropy, probably much less, but never more. 12 is the minimum acceptable, and the bigger the better (the fact that many people use < 8 is no excuse); 2) so I read from the documentation it is not necessary to pass these options cost and salt pro password_hash, because the values he uses by default are already good enough (and if the person does not know what he is doing, he will end up passing worse parameters). And salt is already part of the hash output, you don’t need to store it separately.

  • @mgibsonbr thank you so much for the comments. Corrected!

9

The MD5 is safe, but it is exaggerated to say that it is the best. Therefore, by responding directly, it is not the best. But it doesn’t mean you can’t use and you should change everything where you’re using MD5.

You will probably find recommendations to avoid use as if it were something extremely insecure and easy to circumvent. But what happens is an unnecessary outcry.

Challenge! Let’s prove in practice that MD5 is easy to break?

Let’s see here, a challenge for those who claim MD5 is insecure and easy to discover a combination.

We have this string MD5: bc99449990cd1dedd0b3af807f862fbe

Try to decipher. It is also valid if you can find a collision. Since it is so easy to "break the hash", then it should be an easy challenge. rsrs

This is the hash of the same string in sha1:

6cc0d1e3259b4a7df3b3609207842a08332357b4

Here the same in sha256:

562e5a05b801149cb70092fd1335bb6f40320b44bd7873fb7c05ee1e05f5a606

Of the 3 above, sha256 is obviously safer. If you can use sha256, use it instead of MD5.

The problem is the hash or password?

Note that a weak password of type 12345 is as insecure in MD5 as any other hashes. There is no advantage to using a modern and recommended hash if the system allows weak passwords.

To decipher a hash are used Brute force techniques. The Brute force programs have 2 tables. A table contains obvious words used in passwords like "root", "123", "password", "pass", "admin", etc.

The second table is called "Rainbow table".

The logic is to check if the hash exists in the tables and return the respective string that generated that hash. Simple as that. All known hashes are vulnerable. What will differentiate the level of security is the size of the hash, use of salt, complexity of the original string and collisions.

MD5 has "only" 32 characters. This implies a higher number of collisions. And that is where the biggest problem of MD5 lives.

What are the collisions?

For example, let’s suppose that 1234 manages the hash dfji34iudhfkjfdbn.

The collision occurs when another combination of strings generates the same hash as another combination. Suppose 5%sdi¨¨4dd89 $$Fi9w孤nrrピfe0e90にnf+nbs generate the same hash dfji34iudhfkjfdbn. Ready! We have a collision! Even if you haven’t discovered the original string 1234, ended up going through authentication because it encountered a collision.

(important: the above hash is merely illustrative, with didactic fineness)

There is also the fact that MD5 is generated faster, which makes it "less difficult" to generate combinations. Notice that I prefer to say "less difficult" than to use "easier", because, easy is not.

Note that combinations of all existing characters can take years, decades or centuries depending on the computers you use as it requires a lot of data processing power.

Refer to this old reply as an add-on: /a/96652/4793

Brute force

Okay, now let’s assess the environment. To find a combination for a given hash you need direct access to the data because the method consists of Force, i.e., brute force attempts.

A website, for example, should not allow multiple login attempts in less than 1 second, for example. When it detects something like this, the system must block the login. Therefore, via the web, submitting data by GET, POST, it is impracticable for a hacker to apply Force. Unless the site is very bad and allows such action. At this point is not the fault of the hash used, but of who made the system. In addition there is also the cost of request time and response, making executions slower. Therefore, in the web environment is simply unworkable.

Another point is that you should usually have a combination of username and password. Even if you can figure out a combination of a hash you still have to match the username.

if ( user == 'foo' && pass == MD5('senha') )

Therefore, it is exaggerated the boast they make about the alleged lack of security in the use of MD5 because depends on the context, of ambience, of situation, of circumstance, etc..

Hacker has direct access to database and system

Let’s assume the hacker got direct access to the database and the system. Okay, now he can use Brut force to decode a password. Ok, but think about it. Why would the attacker want to know the password if it’s already inside the system? What’s the point? If you normally want to steal something, the subject will not waste time playing with a password. He goes right where he interests. At this point, with direct access to data, passwords and the authentication system are useless. And even if you still need a password to, for example, access a system where he could not hack, he can modify the email from an account to an email where he has access and so request the password exchange. Bingo!

So where the use of MD5 or a "weak" hash should really be avoided?

A hash considered vulnerable should be avoided in cases such as a digital signature, a public key, among others. Data that is publicly exposed. Because in such cases, the hacker has no job in having to hack into the system. Just grab the hash and search for combinations. SSL uses public and private keys, for example, because it needs a public ID to authenticate with the private key.

Therefore, it is exaggerated and senseless to worry about passwords of a website, within this context that we are addressing. Unless the passwords have a specific use purpose other than to authenticate to access data on this site. For example, if the password provides the access key to a third-party system.

  • 1

    You start by saying that MD5 is safe, but this goes against a bunch of OS replies en http://security.stackexchange.com/questions/19906/is-md5-considered-insecure, http://security.stackexchange.com/questions/52461/how-weak-is-md5-asa-password-hashing-Function, http://stackoverflow.com/questions/16713810/how-secure-is-md5-and-sha1.

  • Yes, the text begins with this phrase followed by 66 lines of text explaining in detail the entire context that is formed by 5518 letters. Could you at least read half? By the way, all these links from the OS you posted speak the same as I posted here. The problem of collisions.

  • You also say that "it’s not easy to generate combinations" "needs a lot of processing power", yet generating hashes by GPU is absurdly fast, for example here has a discussion about using them to generate 110 million hashes per second.

  • If you haven’t noticed, I left a challenge above. Prove to me that you can get the combination of the hash I put in the text. In fact, this is not even the relevant part because there is a larger context that is the use for website. Just read the entire text. Do not interpret isolated passages. It’s all part of the context of the 66 lines of text. Anyway, it’s all explained above. I won’t explain again in the comments.

  • @Brunorb, just read the answer carefully and you can understand that it doesn’t make sense what you’re saying. I am not inducing anyone to anything, in fact I recommended using a better hash. In another comment you say vamos ignorar que a maioria da população usa a mesma senha em 100 sites diferentes. If you had read it carefully you would realize that the answer also talks about it, but it is in summary form pointing to a link in another question where I answered on the subject. There is no problem in the text I wrote. The problem I see is that it is forcing the bar leading to a pejorative interpretation.

  • 3

    I did not give -1, but the reasoning about when the hacker has direct access to the system is totally wrong. When you talk about safety, you always have to consider yourself the weakest link. For example, I know that many of a bank’s employees are registered in a lame Facebook app. If I hack into that system and recover, say, five passwords, there’s a good chance that at least one of them is the password that the person uses in other accounts as well and I can follow that and get to a valid bank password.

  • 1

    In addition, passwords up to 8 characters with raw MD5 applied are feasible to break by brute force as exemplified here. In this case, the problem is not the password.

  • The MD5 collision vulnerability is irrelevant in the context of the password hash (it would be relevant if used directly in a digital signature scheme, for example). The property that matters in this scenario is the pre-image resistance, and in this the MD5 has not yet been broken. The biggest problem with MD5 is not its small output, but the fact that it is quick - I don’t know if it is feasible to break your "challenge", I won’t pay to see. But if it is breakable, it is much easier to break if it is in MD5 than in a slow hash.

  • 1

    Another thing, about the hacker having access to the system, one thing is that he has passive access (say, he used an SQL Injection for the entire content of the bank, but there’s no way to break into the actual server) and another active access. The hash protects against the first scenario, this is its main reason to exist (otherwise, hasehar so, save in plain text even...). A secondary function is to protect the password itself - because in practice many users reuse passwords (and of this crime I myself am guilty), an attack on a weak server could end up compromising.

  • @migsonbr, if you read carefully the reply would not have posted such comments because in the reply I mention the same.

  • now that I read the comment from utluiz also... it seems that the staff does not read right...

  • 1

    @Danielomine Of course I read your answer, if I hadn’t read it I would have been negative for the first sentence rsrs (there’s still time!). And no, neither you nor anyone else on this question seem to realize that collisions are irrelevant in the password hash (even with a "only" 32 byte output). As far as I know, "accidental" collisions (i.e. not made deliberately) of MD5 have not yet been observed in practice. As for the second comment, at what point do you mention it? I put it as an add-on, not critical, because what you say about "hacker with direct access to the system" is correct but incomplete.

Show 7 more comments

3

MD5 is not a good option to encrypt passwords for several reasons. It is certainly better than nothing, but it is not a "serious" protection. Some reasons are MD5, others the type of algorithm it is.

1) MD5 is a hash algorithm with several weaknesses, or at least has had several weaknesses discovered. It is not recommended to use MD5 to check the integrity of a document, as there are ways to generate another document with the same MD5 easily.

2) To encrypt password with hash, you must at least use a salt. Otherwise, it is easy to use a "Rainbow table", i.e., a list of precomputated hashes with common passwords. For example, if you search for 455c99907225a26d1a6e3fa2ce99c9c0 in Google, you will find that this is the MD5 of the word 'sux'. That is, if I had used MD5 to encrypt the password 'sux', it would be trivial to discover the original password!

salt or spice is added to the original password before calculating the hash, so that the hash is different for each user and password. For example, the 'saltsux' MD5 is 5b599ee9dbeb7d6469fa9c300cad07cc, that you no longer find by doing a simple Google search, and even if an attacker knew that salt is equal to 'salt', it does not help much when calculating the hash. Obviously, salt should be random and different for each user, using a fixed and short salt was just a silly example.

3) Hash algorithms in general (MD5, SHA1, SHA2, SHA256, etc.) are designed to run as fast as possible. This makes another form of attack possible: calculating the hash of numerous words (with 'salt') to try to find the hash that matches your system - and thus discover the password.

To avoid this problem, one should use specific hashes to encrypt passwords, such as bcrypt, which consumes a lot of CPU and time to calculate the hash. An opponent who wants to try several hashes would waste a huge amount of time calculating each possible hash.

Bitcoin uses a curious scheme to consume a lot of CPU in the hash calculation. It uses SHA-256, which is very fast, but the hash must have a number of zeros (bits 0) at the beginning. The number of zeroes is calibrated so that the hash takes an average of 10 minutes to find. This is a strategy that could also be used to, from a fast hash algorithm, create a 'slow' hash algorithm, which would serve as passwords.

  • Great answer! About Bitcoin, the purpose of the hash in this case is very different, so there is no way to compare one thing to another. The problem with using a similar strategy to protect passwords is that checking the hash would be costly for both the attacker and the server itself - and we want it to be expensive only for the attacker. Because if the server cannot store the random prefix (or the attacker would also get it along with the hashes), how would he check if a password matches a hash without doing the whole operation again? : P

3

Very well put the answer of @daniel-Omine.

I agree that the md5 is not so insecure, no use having a super-secure login system, which blocks multiple login attempts, etc if we have you user. I’ve read somewhere (and I agree) that the most insecure part of a system is users. Hardly in a system will not have a user even who will use a rough password, commonly used, and use that same password to log in the email registered in the system and the rest is easy to predict. I do not recommend md5 since there are better alternatives like the password_hash.

I know that many do not care about this problem that will always exist in systems that do not foresee weak passwords, but hinder the work of possible invaders, it is a good start.

  • No, the problem is usually the programmer. The user only does what the programmer allows.

  • I did not focus correctly on the "Mr User" part. In this case, the invasion of a database would not be applied directly, but on a given system. It would be something more related to Social Engineering.

3

2

MD5

md5 generates an alpha-numeric string of 32 characters, no matter if you are generating the md5 of two letters or a text of 20 paragraphs... The generated md5 will always have 32 characters.

SHA1

The other one-way hash is sha1. It is practically identical to md5, but has 160 bits, which ends up creating a larger string-result: 40 alpha-numeric characters. Another point of sha1 is that, because it is 160 bits and generates a larger string, a collision (find two strings that, encoded, are the same thing) is much rarer than a 128bit key.

http://blog.thiagobelem.net/criptografia-no-php-usando-md5-sha1-e-base64

Browser other questions tagged

You are not signed in. Login or sign up in order to post.