Diffie-Hellman is a key exchange algorithm. The good question to ask is: exchanging a key, yes, but with whom ?
From a network point of view, you "see" other people only through the packets they send to you; and since everybody can buy the same kind of PC, everybody can send the same packets -- except that some people/system may know some values that other do not. In cryptography, knowledge is power, meaning that you are what you know. If you begin to exchange data with Alice, you know you are talking to Alice and not to Bob because Alice can send some message to you which could have been computed only by someone knowing some given value, and you somehow know that there is someone called "Alice" who knows that value, and someone else called "Bob" who does not.
If, in your model, you don't at least define that there are several possible interlocutors with distinct knowledge, then the notion of "man-in-the-middle" does not even make sense, because all other people, in that model, are identical. If you want to talk about man-in-the-middle attack and how to avoid them, then you must first define who you want to be talking to, and that entails specifying what that system/person knows, that the attacker does not.
In short words: MitM is a special case of impersonation (a double-impersonation, even), where an attacker assumes the identity of somebody else. So you need a notion of "identity" before beginning to discuss MitM attacks.
Now suppose that you have defined a notion of identity. E.g. you are a Web browser and you are trying to reach a URL
https://www.example.com/foobar.html. Then the notion of identity is "whoever controls the
www.example.com server, as registered in the DNS".
Diffie-Hellman is a key exchange algorithm. This means that it does not include, per se, any kind of authentication. This does not mean that DH is useless; only that it is unlikely to provide alone the entirety of the security feature that you seek to obtain. In practice, several cryptographic algorithms are assembled in a protocol such as SSL/TLS.
Back to our example, Diffie-Hellman is indeed widely used in SSL/TLS, with the "DHE" cipher suites. The whole tower of cryptography looks like this:
- The server has a public/private key pair fit for signatures (RSA, DSA, ECDSA...).
- The server generates its half of the DH key exchange, then signs it (with its signature private key), and sends that to the client.
- The server also sends its signature public key to the client, as a certificate issued by some CA.
- The client validates the certificate (because the client already knows and trusts the CA) and thus learns the server's public key.
- The client verifies that the server's certificate contains the expected server name (here:
- The client verifies the signature on the half-DH sent by the server, using the server's public key.
- The client computes its own half-DH and sends it to the server.
- The client and the server complete the DH computation and obtain a shared secret, which is then expanded into symmetric keys for encrypting all the data.
The notion of identity used by the client is that a server owner cannot obtain a valid certificates from a trusted CA unless he effectively controls the relevant domain. So, from the point of view of the client, the "genuine
www.example.com server" is "whoever knows a private key corresponding to a public key in a certificate from a trusted CA and containing the
www.example.com name". The knowledge of the private key is what makes the server "the right one". The CA links that key (the public key, specifically) to the DNS name.
What protects against MitM here is that the man-in-the-middle does not know the private key (he could generate private keys of his own, but they would not match the public key in the certificate). The signature is the mechanism by which this protection is enacted. That's not Diffie-Hellman which provides that protection. On the other hand, the signature does not result in a shared secret: that is the job of DH.
Summary: you want to obtain a shared secret with some specific server, so that you may encrypt gigabytes of data to be sent to that server. This is a two-parts job: you want a shared secret, but it also has to be with some specific server. DH does the "shared secret" part. You need something else for the other part, e.g. some signature algorithm. This is what happens in SSL or SSH.