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:
- Lock out a user after X failed login attempts. Problem: easy to turn into a denial of service attack, locking out many users in a short amount of time.
- Incrementally increase response time per failed login attempt on a username. Problem: dictionary attacks might use the same password but different usernames.
- Incrementally increase response time per failed login attempt from an IP address. Problem: easy to get around by spoofing IP address.
- Incrementally increase response time per failed login attempt within a session. Problem: easy to get around by creating a dictionary attack that fires up a new session on each attempt.
I like gmail’s anti-brute force system a lot. It is based on “heat” that a user can accumulate, after the user has overheated they are prompted with a captcha. You can keep track of heat using a sql database, or using redis incr. Heat is assigned to an ip address. It is 100% impossible to “spoof” a tcp connection over the internet because of the three-way-handshake, however proxy servers are plentiful and ip address are very cheap. Proxy servers are commonly used to send spam, you can check a blacklist and automatically prompt them for a captcha.
Each bad action against your system will update the heat table. For instance a failed login will accumulate 35% heat. Once the heat level is greater than or equal to 100% then the user is forced to solve a captcha. Solving a captcha will “cool down” that ip address. The heat table could contain a timestamp column that is set to the current time on update. After 24 hours or so the heat can return to 0.
reCaptcha is the most secure captcha you can use.