What\'s the best way to prevent a dictionary attack? I\'ve thought up several implementations but they all seem to have some flaw in them:
I've always been a fan of your option 3 - locking out or throttling a client based on its IP address. The other options are all more trouble than they're worth for the reasons you've stated.
Spoofing an IP address is possible, but it does not defeat this counter-measure. If you mean "spoofing" in the technical sense - forging the TCP packet header - then that won't do the attacker much good, because even if they guess the correct password they won't receive the response that tells them so. They could still use proxies, of course, but the number of proxies is limited. Even if an attacker has 1,000 working proxies at his disposal and you allow 10 attempts per IP that's 10,000 attempts. If you enforce any password complexity at all (such as requiring an alphanumeric password) then this won't be enough to guess much.
That alone should be enough to stop most script kiddies. If you are up against a more determined attacker you would probably have to implement some sort of site-wide monitoring which detects that there are many attempts being made (so there's probably an attack going on) and "locks down" in some way, eg. by using CAPTCHAs. I'm not a fan of using CAPTCHAs all the time - they're just more annoyance than they're worth.
Ultimately, it's up to the user to choose a secure password (though you can help them). If they've chosen "Password1" as their password then nothing you can do will stop a hacker from breaking into their account.