3

I have questions regarding the best way to secure the authentication of users.

I have come across a web application that encrypts the user password in the back end. However this encryption is done with the same key to all passwords. Also, this key is "hardcoded" in the back end.

They (the app developers) claim that this is perfectly secure. However I have my doubts. I believe that this method can cause two problems:

  • The reason to encrypt passwords is to avoid access to the passwords in the event of an unauthorized database access. However if you store the key in the same server chances are they will also be able to obtain the key.

  • The same password will yield the same encrypted value therefore it will be easier to attack the system.

My questions are the following:

  • Am I right about my claims? And if it is really that insecure, should I warn them about the possible threat?

  • What would be the pros and cons of using a hash + salt approach instead?

Thanks!

Felipe Sulser
  • 1,185
  • 8
  • 19
  • Yes, passwords that are encrypted can be decrypted and therefore are vulnerable if access is gained to the system. Passwords that are salted and hashed do not have that exposure. – dbugger Apr 27 '16 at 14:22
  • 1
    Your critique is absolutely right. You have already warned them. Whether you should persist depends on context only you can fully evaluate. There are no cons to using a salted hash. It's the correct way to perform password authentication. Storage *encrypted* passwords is a special case, like a password manager, where an individual is encrypting their own credentials with a master key. It's absolutely the wrong solution for authentication. – erickson Apr 27 '16 at 19:02
  • Thank you @erickson. I see that using hash+salt really is the best solution and it isn't any more complex to implement than an encryption scheme. – Felipe Sulser Apr 27 '16 at 19:40
  • @FelipeSulser That is indeed the way to go :-) – Juxhin Apr 27 '16 at 20:01

2 Answers2

4

I'm not sure if you might mistakenly mixed up encryption and hashing together. If the user's password is be encrypted and not hashed then there is potential for an attacker to steal all the user password in the event of a data breach.

There are a number of factors that you seem to be looking over when it comes to authentication. Firstly, any hashing should be done in the back-end and never in the front-end. Hashing in the front-end still leaves you vulnerable to hash attacks.

Some developers adopt a double-hash approach in which they hash the password in the front-end and then re-hash it in the back-end. I believe this is unnecessary, the front-end password should be covered by the HTTPS layer (TLS), however that is subject to discussion.

First, let's clarify two key terms before explaining how to securely store and authenticate users.

Encryption

You specify that the user's passwords are being encrypted, rather than hashed. What encryption functions do is map an input (user's password) to an output (encrypted password) in a 1-to-1 fashion, meaning that this is reversible.

This means that if the hacker gains access to the encryption key (private key), they can reverse the entire process easily.

Hashing

Instead, the user's password should be hashed on the server-side. Why? Because you can get away with comparing two hashes to check whether they match without ever storing the plain-text representation of that value.

And once again, you may be asking, "Why"? Well because hashing functions are one-way, meaning that the plain-text value cannot be reversed (well, they are very hard to), I shall not be going into to much detail.

What should I do?

The user's passwords should never be stored as plain-text in any part of the web server. Instead, you should be storing the user's hash. When the user then tries to login, you receive their plain-text password securely over HTTPS/TLS, hash it and if both hashes match, authenticate the user.

So a database table might look like so:

+--------------------------------------+
|  ID  |  Username  |   Password Hash  |       
+--------------------------------------+
|  1   | foo        | $2a$04$/JicM     |
|  2   | bar        | $2a$04$cxZWT     |
+--------------------------------------+
  • Note, the hashes are truncated BCrypt hashes with 4 rounds (AKA - Invalid)

Now let's take an example, between Alice and our server. Don't take the data too literally.

Alice sends a request to login with her credentials, which first passes through our secure transport layer:

{username: "foo", password: "bar"} -> TLS() -> ZwUlLviJjtCgc1B4DlFnK -> | Server |

Our server receives this, then uses it's certificate key to decrypt this:

ZwUlLviJjtCgc1B4DlFnK -> KEY() -> {username: "foo", password: "bar"} -> Web Application

Great! Our credentials have been passed securely, now what? Hash that password and compare against what we got in our database.

BCRYPT('bar') -> $2a$04$/JicM

if ($2a$04$/JicM == user.get_password_hash) {
    authenticate();
}
else {
    return status_code(401);
}

We have now been able to authenticate a user, storing an irreversible hash value and without ever storing the plain-text value. This should have answered your first and second question.

Juxhin
  • 5,068
  • 8
  • 29
  • 55
  • Nice and thorough definition. Although I knew the concepts of hashes and encryption already it is a complete definition with the main advantages of the hashing. Thanks! – Felipe Sulser Apr 27 '16 at 20:05
  • @FelipeSulser - That's great, often people mix the two and I thought it would be beneficial to explain the main differences between the two before tackling your question directly. Glad you found it helpful :-) – Juxhin Apr 27 '16 at 20:07
0

Yes, your analysis is correct, this is insecure.

It would certainly fail any formal audit, e.g. PCI-DSS. the developers/operators may argue that the asset these accounts provide access to is of little value and hence they have no need to provide such a level of protection, however they still have a duty of care to their customers - and the majority of people will use the same password for different sites/services.

It does provide a means for users to "recover" their passwords without the complexity of creating an expiring OTP - however mailing a plain text password further undermines security.

Indeed, even if an attacker only had access to the encrypted password data (particularly if it contained a known encrypted value / does not use initialization vectors) it may be possible to derive the encryption key.

symcbean
  • 47,736
  • 6
  • 59
  • 94
  • 2
    While I agree with your answer, the last paragraph is wrong (you've used *may*, but it's still highly unlikely). If a key can be deduced from many plaintext-ciphertext pairs, then this symmetric cipher is broken and should not be used in any case. AES, the most commonly used cipher, is not such a cipher. – Artjom B. Apr 27 '16 at 15:10
  • Agreed the choice of cipher has an impact - but we don't know what cipher is being used here. Also, with no IV and multiple short messages, the encryption is effectively in ECB. – symcbean Apr 27 '16 at 15:57
  • But wouldn't it be easier to break it? For example if two rows of the table contain the encrypted password x and for one, the password hint is "Dog name", and for the other one it's "Favorite meal" you may assume that the answer is Meatball. It may be easier to break. Right? – Felipe Sulser Apr 27 '16 at 17:38
  • @FelipeSulser It would be easier to guess those two passwords, but won't be possible to recover the key and decrypt all the other passwords with it. The exploit you describe is possible with any password authentication scheme, which is why password hints are insecure. – erickson Apr 27 '16 at 19:07