13

I have TLS connection between my server and client. I have no certificate, so the connection is susceptible to the Man-in-the-middle attack.

I fear that attacker could intercept the password hash and use it to authenticate himself in my application.

What is the best way to transmit password hash? To use server nonce or client nonce? And what hashing algorithm should I use?

JohnDvorak
  • 107
  • 5
Igor
  • 133
  • 1
  • 5
  • 3
    I presume that the exact attack scenario you're worried about is: "I've self-signed a certificate and I'm concerned that if someone gets my CA, they can impersonate my server and stage a MITM." Is that your scenario? Or do you inherently distrust _all_ CAs? – Naftuli Kay Jan 27 '15 at 21:18
  • Is the client a proper application, or a website? In the first case you can simply act as your own CA. – CodesInChaos Jan 28 '15 at 09:51

5 Answers5

27

You can't.

There is no secure way to transmit it if you can't authenticate the server and establish a secure channel. If you can't authenticate the server then you can't be sure if you are talking to the server or the attacker. Hence, even if you use TLS to establish a secure channel, it doesn't protect you at all since you could be talking to the attacker while thinking that you are talking to the server.

The certificate is essential. Without it, or some knowledge of the public key of the server, you cannot be sure that you are really communicating to the server as an attacker could act as a man in the middle between you and the server.

TLS use Diffie-Hellman for the key exchange. If you look at the security section of the wikipedia page you will find the following attack which is exactly what you are vulnerable to.

In the original description, the Diffie–Hellman exchange by itself does not provide authentication of the communicating parties and is thus vulnerable to a man-in-the-middle attack. Mallory may establish two distinct key exchanges, one with Alice and the other with Bob, effectively masquerading as Alice to Bob, and vice versa, allowing her to decrypt, then re-encrypt, the messages passed between them.

Conclusion

You need to have a valid certificate to be able to authenticate the server or you will be vulnerable to man in the middle attack. An easy way to achieve that is to include the server certificate in your application which is also known as certificate pinning.

Gudradain
  • 6,921
  • 2
  • 26
  • 43
  • 4
    I was thinking of answering with the lines of "Ditch your unreliable TLS", but you did it better. – Mindwin Jan 28 '15 at 15:03
27

You should look into Certificate pinning.

This is effectively allowing you to trust your self-signed certificate, and that server certificate only from your client by a hard lookup of the public key of the certificate. So the chain of authority is not followed (which is where a self-signed certificate falls down) and instead the public key is validated by the client application to be trusted directly.

You should not look at hashing, or anything else on the application layer as it will be inherently susceptible to a MITM attack.

SilverlightFox
  • 33,408
  • 6
  • 67
  • 178
  • 1
    Well, you _should_ hash, just on the server side and to protect the password in storage instead of in transit. – cpast Jan 28 '15 at 03:16
  • @cpast It's usually recommended to hash on the client side so that the password never gets sent over the wire in the first place (encrypted or otherwise.) In a ideal setup, the server should never actually know the password, but only its hash. – reirab Jan 28 '15 at 17:15
  • +2 for the first 2 paragraphs, -1 for the last paragraph. :) You definitely should hash passwords, but that concern is orthogonal to the need for verifying that the server really is who it says, which is solved by the suggestion in your first two paragraphs. – reirab Jan 28 '15 at 17:17
  • 2
    @reirab: The 3rd paragraph was in the context of defeating a MITM. If you send a hashed password over the networking application layer, the hashed password effectively becomes the password. I'm not saying that hashing is a not a useful concept _at all_ if that is the impression you got? – SilverlightFox Jan 28 '15 at 17:26
  • Ah, yes, I got the impression that you were saying to use certificate pinning _instead of_ hashing the password, rather than in addition to it. Obviously, hashing the password does not prevent MITM attacks, but it does prevent someone (including authorized administrators on the server) from finding your original password, which may be used in other places (assuming, of course, that the hash is salted.) – reirab Jan 28 '15 at 17:31
  • 4
    @reirab No, it's just about always recommended to hash on server side. You always need to hash on the server side anyway, because otherwise the hash *is* your password, and a compromise of the database compromises your site credentials. The server gets the password and immediately verifies it; no administrator can see that password, unless they modify the code of the webpage to save the password elsewhere. – cpast Jan 28 '15 at 18:32
  • But if they're able to modify server code, they can also do a whole host of other things - for instance, since the application needs to get the salt from the server, someone modifying server code could send a fixed salt for everyone (instead of the real salt), harvest the hashes, and then have an essentially unsalted list of hashes vulnerable to precomputation. – cpast Jan 28 '15 at 18:33
13

Bundle your self created root CA certificate with your application and configure it to reject all untrusted certificates. If you only use your own CA cert, this is arguably more secure than relying on the normal CAs, since CAs have been compromised in the past by attackers, and are subject to government authorities and politics as well.

Rolling your own authentication scheme is foolhardy, and is almost guaranteed to be less secure than simply using TLS with a bundled certificate.

Steve Sether
  • 21,480
  • 8
  • 50
  • 76
  • Indeed. Recognize your own root cert. If you get anybody else's cert, trust chain or not, IMMEDIATELY reject it as invalid. No bypass option. (Oh, and set the expiration date for the root cert to the highest allowed value by X509 format.) – Joshua Jan 28 '15 at 17:00
  • Can i revoke and reissue this certificate if it gets compromised? – Igor Jan 29 '15 at 10:24
  • 2
    @Igor Yes, but you have to put the revocation list in the cert when you create it, and you have to put certificate revocation support in your app http://blog.didierstevens.com/2013/05/08/howto-make-your-own-cert-and-revocation-list-with-openssl/ – Steve Sether Jan 29 '15 at 15:47
2

Since others have already mentioned about TLS authentication and what can be done regarding that problem, I'll just focus on:

What is the best way to transmit password hash?

MITM is one of the threats in your scenario. Another possible (also very common) threat is a Data breach. You must consider the case where your database might be compromised and must take necessary precautions on the server side as well. Hashing passwords on the client-side is not a very good idea, unless you do not trust the server with your passwords and you are hashing them again on the server. I guess it is not the case with your scenario because the server is your own.

If the password hashes, sent by the clients, are stored as-is in the database, an attacker can impersonate all users by sending the server the hashed passwords from the database as-is. Hashed passwords will merely serve as secret access tokens in this case. Read this for more details.

And what hashing algorithm should I use?

Some good hashing functions (for storing passwords on the server) include bcrypt, scrypt and PBKDF2. Take a look at Thomas Pornin's awesome answer for why these are better. Basically, these functions, if used properly, will make the task of an attacker much more difficult in case of a data breach.

Rahil Arora
  • 4,259
  • 2
  • 23
  • 41
  • `"Hashing passwords on the client-side is not a very good idea..."` Can you expound on this assertion? Under what scenario is there any drawback to hashing on the client side? Also, what need does the server have to ever know a user's password in the first place? Transmitting the password to the server, even encrypted, is still opening up more possible vectors for the password to be compromised. What benefit offsets this disadvantage? – reirab Jan 28 '15 at 17:24
  • @reirab: The link in my answer already does that (edited my answer anyways :-)). If the hashed password database is compromised (in case of *just* client side hashing), those hashes will merely act as an Access Token. These token can be then used to authenticate to the application. – Rahil Arora Jan 28 '15 at 18:19
  • The most upvoted answer in your link recommends hashing on both sides... – reirab Jan 28 '15 at 18:37
  • 1
    Yes. Indeed. The point is, you must hash on the server side no matter what. Since the OP asked for recommendations regarding hash functions, that's what I included in my answer (since other answers didn't cover that). – Rahil Arora Jan 28 '15 at 18:54
1

Use SRP (Secure Remote Password) mechanism of TLS.

The client and server authenticate each other based on knowledge of a shared password which is never sent (this means that whatever you use as password -in this case the hash- will have to be stored in plaintext by the server).

Ángel
  • 17,578
  • 3
  • 25
  • 60