"The ideal cryptographic hash function has four main properties:
(a) it is easy to compute the hash value for any given message
(b) it is infeasible to generate a message that has a given hash
(c) it is infeasible to modify a message without changing the hash
(d) it is infeasible to find two different messages with the same hash."
MD5 fails (b), (c), and (d).
One additional problem is due to the length extension attack: http://en.wikipedia.org/wiki/Length_extension_attack
For MD5 and SHA-1, given any hash, it's possible to reconstruct the internal state of the hash function. (They're named "hash function," but "hash state machine" is probably a better way to think about it.) For example,
MD5("The quick brown fox jumps over the lazy dog").hexdigest() => 9e107d9d372bb6826bd81d3542a419d6
Given 9e107d9d372bb6826bd81d3542a419d6, you can reconstruct the internal state of MD5, allowing you to continue hashing data. For example, you could add " while the cow goes moo:"
MD5("The quick brown fox jumps over the lazy dog while the cow goes moo").hexdigest() => ab7e4a96438e33094a7df3d41fa89c47
MD5_FromHash("9e107d9d372bb6826bd81d3542a419d6").append(" while the cow goes moo").hexdigest() => ab7e4a96438e33094a7df3d41fa89c47
Ideally, you'd like to be able to reveal the hash publicly without revealing any details about the internal state of the hash algorithm. (It's my understanding that SHA-3 accomplishes this goal automatically.) Another way to accomplish that goal is to use HMAC-MD5 or HMAC-SHA1. At that point you can prove that you hashed something by prepending a secret key to the data. For example,
HMAC_MD5("My 256-bit random secret key", "My message to be hashed").hexdigest()
This would yield a hash value that you can reveal publicly, and which no attacker can append any data to. For any given data D, you can verify that you generated the hash value by computing
HMAC_MD5("My 256-bit random secret key", D).hexdigest()
and comparing it to the other hexdigest. If they're equal, then either some attacker has stolen your private key or you generated the hash.
But if you tried this with plain old MD5, then an attacker can easily append data and trick you into thinking you generated it.
This is actually all the time I have right now, so someone else please feel free to step in and fill in missing details, such as how to find two different messages which hash to the same MD5 value.