1. Use memcached or asp.net cache to detect if a high number of login attempts are happening, if so, implement a 1 to 2 second sleep on each login attempt for 15 minutes (with some additional per IP slowing).
2. Put a sleep for 500ms on all login attempts.
I've been doing both for a while, with the thought that they are effective methods in conjunction with proper hashing.
This protects against people who are attacking your app through its public login interface, but when a file containing your hashed passwords gets stolen the thieves will attack the passwords directly.
This sounds like a reasonable addition to your security arsenal, and it should help to ensure that your own app is not being abused to brute-force your users' passwords. However, it doesn't provide you any protection if your database is compromised, and that is really when your hash security is most important.
You do mention this in addition to "proper hashing", so I'm sure you recognize this as well, but I think it is important to emphasize secure hashing practices before any talk of securing your app's login endpoint itself.
1. Use memcached or asp.net cache to detect if a high number of login attempts are happening, if so, implement a 1 to 2 second sleep on each login attempt for 15 minutes (with some additional per IP slowing).
2. Put a sleep for 500ms on all login attempts.
I've been doing both for a while, with the thought that they are effective methods in conjunction with proper hashing.