If my website uses a POST form for login, what is a quick and easy way to prevent a rogue client from flooding my web server with POST requests trying to brute force crack my user accounts?
PHP/MySQL/Apache.
If my website uses a POST form for login, what is a quick and easy way to prevent a rogue client from flooding my web server with POST requests trying to brute force crack my user accounts?
PHP/MySQL/Apache.
Well, if you know the IP of the source of the login attempt, you could allow it 5 attempts, then make that IP wait through a 5 minute "cool-off" period. If you think 5 minutes is too short, raise it until it's something more suitable (could go as high as 24 hours, or more if you think it's necessary). This might not work as well if they have dozens of coordinated nodes in a botnet.
One approach is to keep track of the IP address (or even of the first 3 octets of the IP Address) of each request and to add a significant time in responding to (or even to drop) the requests coming from IPs that have had more than x requests in the last y minutes.
This is ineffective (or less effective) against distributed attacks, but otherwise work quite well, for a relatively simple implentation.
For a stronger proptection, one can also blacklist offending IPs (IPs, or again first 3 octets of IP, which have submitted more than say 6 bad attempts in the last 2 minutes or less) by systematically denying access to such IP for a period of say 15 minutes.
If your login form sends a passkey/fingerprint with the post request you can have the php code check if that is valid when receiving the post data before you connect to the database to check passwords.
if ($_POST['fingerprint'] == $fingerprint) {
connect(); //etc
}
The fingerprint is a string variable which is passed from your login page in the post value, but invisible to the user. The code which checks the validity of the login attempt will check the fingerprint against it's own known good one. If they match then it can continue to access the database and compare login credentials etc. As suggested in the comments, it would be even better if it was dynamically generated.
This way a malicious script would need to have the fingerprint to even try to access your site.
The other option would be having a session variable to record the number of tries in a certain period.
Preventing brute force cracking is trickier than it may at first seem. The solution will be to combine controls - one single control will not cut the mustard. And remember the goal: you want to slow down a brute force attack to the point where it will either be ineffective, or you can detect it and take action. The second option is generally more effective than than first.
You could use a captcha (this is currently a popular technique) but captchas can often be automatically read, and when they can't be read by a computer, farms of people can be be obtained by paying low waged workers or by using the captcha to protect "free" porn (both techniques have been used).
The advice of others to use a secret value in the form won't really help; an attacker simply has to parse the HTML to find the secret value, and include it in their post. This is pretty simple to automate, so it's not really a good defense. Oh, and if the value turns out to be easily predictable (using a poor or broken PRNG or a bad seed) you're up the creek, again.
Tracking the IP address is okay, but only if you don't support NAT. With NAT, valid users will appear to be duplicates. And remember that attackers can impersonate other systems; a single attack system can use other IP addresses, and even intercept the traffic to that system (ARP poisoning is one good mechanism for this).
You could use a max number of failed timeouts in a given period of time (like 3 within 1 hour). This slows the attacker down, but doesn't necessarily stop them. You might include an automated unlock, but you'll need to do some math, and make sure that the unlock time is actually useful.
Exponential backoff is another useful mechanism. This might be possible to tie to a session (which the attacker doesn't have to return to the server) to the IP address (With breaks with NAT) or to the account (which doesn't account for brute forcing across multiple accounts).
For the other defenses to be useful, you have to have strong passwords. If your passwords are easy to guess (are they in a dictionary? are they short? are they complex?) the attack will succeed. It's a good idea to implement minimum password strength requirements, and an "illegal passwords" dictionary (combined with common character substitutions for that dictionary). Alternatively, you might use a system like OATH, certificate login, or hardware tokens (like RSA's SecurID).
I think it was Burt Kaliski who discussed client puzzles. Basically, you give the client a challenge that's easy for the server, but difficult for the client; the client DoSes itself by wasting its own resources trying to solve the puzzle. The difficulty, here, would be in determining the right complexity for the puzzle. It might, for example, be factoring a large number. Whatevr it is, you'd have to assume the most effecient possible algorithm, and you'd have to be able to handle different performance of different browsers on different machines (potentially slow) while slowing down automated attacks outside of browsers (potentially faster than your javascript). Did I mention that you'd have to implement a solution in JavaScript?
But you're still stuck with an attack that works across multiple accounts. I'm not aware of any publicly used controls that work well against this, unless you can track IP addresses.
Then, you'll want to protect usernames. An attacker who doesn't know usernames (requiring a system that doesn't indicate when usernames are valid) will have to learn both the username and the password, instead of easily confirming a username, then just attacking passwords.
And you'll need to be careful that error messages, and server timing don't give away (in)valid passwords, either.
And when you deal with error messages, make sure that password recovery mechanisms don't give anything away. Even in otherwise good systems, password recovery can blow the whole thing.
But, all that said, the attack is ultimately dependant upon the server's performance. You might simply implement a very slow mechanism for authentication (has to be slow for both valid and invalid authns). An online attack is guaranteed to go no faster than the server can process requests.
Then, you need to detect rute force attacks, so your system needs a good audit trail. But you'll need to be careful not to log too many log messages or you'll open up an easy way to dos the server by filling up disk space. Something like syslog's "the previous message has been recieved 1000 times" message would be good.
Once you're all done designing things, and again when you're done implementing things, you'll want to examine the whole system, and all features of the system, mathematically model it given the current settings and the server's performance and determine the average amount of time it would take an attacker to brute force (a) a single account, and (b) any account (brute forcing across accounts to avoid account-specific controls).