views:

329

answers:

4

What is the best way to stop bots, malicious users, etc. from executing php scripts too fast? Is it ok if I use the usleep() or sleep() functions to simply do "nothing" for a while (just before the desired code executes), or is that plain stupid and there are better ways for this?

Example:

function login() {
 //enter login code here
}

function logout() {
 //enter logout code here
}

If I just put, say, usleep(3000000) before the login and logout codes, is that ok, or are there better, wiser ways of achieving what I want to achieve?

edit: Based on the suggestions below, does then usleep or sleep only cause the processor to disengage from the current script being executed by the current user, or does it cause it to disengage from the entire service? i.e. If one user+script invokes a sleep/usleep, will all concurrent users+scripts be delayed too?

+1  A: 

Your suggested method will force ALL users to wait unnecessarily before logging in.

Most LAMP servers (and most routers/switches, actually) are already configured to prevent Denial of Service attacks. They do this by denying multiple consecutive requests from the same IP address.

davogones
+1  A: 

You don't want to put a sleep in your php. Doing so will greatly reduce the number of concurrent requests your serve can handle since you'll have connections held open waiting.

Most HTTP servers have features you can enable to avoid DoS attacks, but failing that you should just track IP addresses you've seen too many times too recently and send them a 403 Forbidden with a message asking them to wait a second.

If for some reason you can't count on REMOTE_ADDR being user specific (everyone behind the same firewall, etc.) you could prove a challenge in the login form and make the remote browser do an extended calculation on it (say, factor a number) that you can quickly check on the server side (with speedy multiplication).

Ry4an
+2  A: 

to stop bots, malicious users, etc. from executing php scripts too fast?

I would first ask what you are really trying to prevent? If it is denial-of-service attacks, then I'd have to say there is nothing you can do if you are limited by what you can add to PHP scripts. The state of the art is so much beyond what we as programmers can protect against. Start looking at sysadmin tools designed for this purpose.

Or are you trying to limit your service so that real people can access it but bots cannot? If so, I'd look at some "captcha" techniques.

Or are you trying to prevent users from polling your site every second looking for new content? If so, I'd investigate providing an RSS feed or some other way of notifying them so they don't eat up your bandwidth.

Or is it something else?

In general, I'd say neither sleep() nor usleep() is a good way.

--
bmb

bmb
+7  A: 

The way most web servers work (Apache for example) is to maintain a collection of worker threads. When a PHP script is executed, one thread runs the PHP script.

When your script does sleep(100), the script takes 100 seconds to execute.. That means your worker thread is tied up for 100 seconds.

The problem is, you have a very finite number of worker-threads - say you have 10 threads, and 10 people login - now your web-server cannot serve any further responses..

The best way to rate-limit logins (or other actions) is to use some kind of fast in-memory storage thing (memcached is perfect for this), but that requires running separate process and is pretty complicated (you might do this if you run something like Facebook..).

Simpler, you could have a database table that stores user_id or ip_address, first_failed and failure_counter.

Every time you get a failed login, you (in pseudo code) would do:

if (first_failed in last hour) and (failure_counter > threshold):
    return error_403("Too many authentication failures, please wait")
elseif first_failed in last hour:
    increment failure_counter
else:
    reset first_failed to current time
    increment failure_counter

Maybe not the most efficient, and there is better ways, but it should stop brute-forcing pretty well. Using memcached is basically the same, but the database is replaced with memcached (which is quicker)

dbr