How about this:
- Store the hashed password on the server.
PasswdMD5 or something), then cat on a sufficiently
random session ID and hash it again. Send that hash
to the server.
- The server takes the session ID, cats it onto its
copy of the hashed password, hashes the result, and
compares that hash to the one it got from the client.
So the server isn't keeping around any plaintext
passwords, and the session ID acts as a one-time key to
prevent replay attacks. For extra tasty goodness, you
can do this through SSL to prevent attackers from
sniffing the session ID, although unless they know the
original password hash (which, since we're not storing
the password in plaintext anywhere, is mildly unlikely)
the worst damage they could do with a sniffed session ID
is chuck a bogus hash back at the server and give the
real user a "sorry, try again" message (if that).
I'm a bit leery of this system, because it seems too
simple. Can you see any problems with it?
Update: Cacharbe expressed some doubts about
the "sufficiently random" session ID. Basically, the
idea is that the server picks a random integer (from
/dev/random or something similar), keeps a
copy, and sends it off to the client. Client hashes
their password, cats the session ID onto the password,
hashes _that_, and sends it back over the wire. Server
cats the (same) session ID onto its hashed password for
whoever the client claims to be, hashes it, and checks
it against the hash it got back from the client.
The problem with this (which I only just saw --
augh!) is that the server's still storing information
that can be used verbatim to attack a client account.
If I can get the hashed password from the server, then
I can just connect, get a session ID, and go from
there. In short, it isn't really a step up from storing
passwords in plaintext on the server. Oh well, back to
the drawing board.