And, well, this is where I just kinda go off the rails, because it seems as if there's nothing that's ever been conceived by man that doesn't have an article by a security expert saying "what are you, some kind of idiot? Why would anybody use that?"
You do face the challenge of sorting through all the noise of proposals and retorts --- "what if I use a 64 bit salt?", "what if I use SHA-256 instead of MD5", "what if I use AES to encrypt the passwords", "what if I run SHA1 in Javascript and just exchange the hashes", etc, etc, etc. None of this stuff matters.
The core issue is: your password hash should be cryptographically slow. It should resist account-at-a-time brute force attacks, which are the predominant method used to crack accounts. You can safely ignore the rest of the sideshows.
And finally, I have to say that just because a topic seems annoyingly complex doesn't mean it morally has to be simpler. If security experts are telling you you're an idiot for doing X, by all means get pissed that they called you an idiot, but also stop doing X.
I'm OK with complexity. What I'm not OK with is the impression I get that there simply is no option that won't get shouted down. "Making the right choice is complex" is fine when compared to "there is no right choice".
In actual fact, I won't even shout at you for using salted single-pass SHA1, as long as you don't brag about it, or talk about how your "salt" construction improves security.
And, in the context of common use cases, I think it's probably an OK compromise -- I doubt somebody's going to devote the resources to plucking the password for a random blog, for example. Once you need tougher security, you can plug in whatever scheme you like for storing credentials and authenticating users which, anecdotally, most people seem to be doing when warranted (there are quite a few third-party auth backends floating around). And, really, if I were going to brag about anything, it'd probably be the ease with which you can do that -- one class with two methods, a settings tweak and (depending on your credential scheme) possibly a short form class that knows what the incoming data will look like, and you're done. Of course, I think we could make it even easier, so I won't be bragging about it just yet :)
1. The "password" field in the DB holds a value of the form "algorithm_name$nonce$hash".
2. "algorithm_name", by default, is SHA1, but the backend lets you also use in MD5 (for backwards compatibility) or Unix crypt if you're running on a platform which has it.
3. "nonce" is the first five digits of the hex digest of a pair of floats pulled (at the time the password is set) from Python's 'random.random()' (which, of course, is a PRNG, not a truly random source of numbers).
4. "hash" is the result of applying the algorithm to the combination of the plain-text password and the nonce.
It's a bit confusingly set up internally because the code refers to the nonce as "salt" even though it's different (within the limits of Python's PRNG) for each stored password. And there's some fun legacy stuff in there that transparently switches naked MD5 hashes over to the algo/nonce/hash scheme when possible, which makes even more fun.
As best I can tell, this is the sort of scheme you're recommending, or at least that you're not outright bashing. Is that correct, or have I missed something?
We've had requests to open up the variety of hashing algorithms supported in the default backend, and AFAIK the jury's still kinda out on that one due to various compatibility issues with existing DBs and older Pythons, and the ease with which alternate authentication schemes can be plugged in.