简体   繁体   中英

How do I protect against ajax-spam in PHP?

Good day,

I would like to know how to protect my website from ajax-spam. I'm looking to limit any ajax action per users. Let's say 8 ajax-actions per minute.

An example of an action would be: a button to add/remove a blog posts "as my favorites".

Unless I'm wrong, I believe the best way would be using $_SESSION 's variable and to avoid someone/a bot to clear cookies to avoid my protection. I'm allowing ajax-functions only to logged-on users.

Using database would make my protection useless because it's the unwanted database's writes I'm trying to avoid.

I have to mention that I actually use PHP as server-language and jQuery to proceeds my ajax calls.

Thank you

Edit:

The sentense

... to protect my website ...

is confusing but it's not about cross-domain ajax.

Edit 2011-04-20: I added a bounty of 50 to it.

Since you're only allowing AJAX actions to logged in users, this is really simple to solve.

  • Create a timestamp field for each account. You can do this in the database, or leverage Memcached, or alternatively use a flat file.
  • Each time the user makes a request through your AJAX interface, add the current timestamp to your records, and:
  • Check to make sure the last eight timestamps aren't all before one minute ago.

From there you can add additional magic, like tempbanning accounts that flagrantly violate the speed limit, or comparing the IPs of violators against blacklists of known spammers, et cetera.

Are you talking about specific ajax-spam to your site, or ajax-spam in general?

If the latter, you can use hashes to prevent auto-sending forms, ie write your hash() one-way function which takes string and makes sha1-checksum of it.

So that's how you use it:

// the page is a blog post #357
$id = 357;
$type = 'post';
$hash = hash($_SERVER['REMOTE_ADDR'].$type.$id);

Put that hash in hidden field which is not within the comment form or even hidden div, somewhere at the bottom of the page, and name it "control_hash" or something. Attach it's value to the ajax-request on form submit. When the form is received by the script, make a new hash from $_REQUEST data (excluding existing $control_hash ) and check if they match.

If the form was submitted by bot, it won't have $control_hash , so it won't pass.

Yes, your idea in principle is good. Some things to consider though:

  • If you track the limits globally then you may run into the issue of a bot DoS ing your server and preventing legitimate users from being able to use your "Favourite" button.
  • If you track the requests based on their IP then someone could use a bot network (multiple IPs) to get around your blocking. Depending on your site and what your preference is, perhaps limit based on a subnet of the IP .
  • Install and use Memcache to store and track the requests, particularly if you are going to be tracking based on the IP. This should be faster than using session variables (someone might correct me on this).

If you have access to the source code of the web-site, you can rewrite some of the javascript code that actually performs AJAX-request. Ie your pages can have a hidden counter field, that is incremented every time a user clicks the button. And also you can have a timefield hidden on the page, in order to rate the frequency of clicks.

The idea is that you don't even have to send anything to the server at all - just check it on the client side inside the script. Of course, that will not help against the bots adressing directly to the server.

It really depends on the result of such a spam. If you just want to avoid writing to your database, all these check could end up taking more ressources than actually writing to the database.

Does the end justify the means?

You also have to judge what's the probability of such a spam. Most bots are not very smart and will miserably fail when there's some logging involved.

Just my 2 cents, the other answers are perfectly valid to avoid spam.

Buy more powerful hosting to be able serve requests, don't limit them. 8 requests per minute it's ridiculous.
Anyway, if requests are 'legal', you should find ways how to serve requests, not how to limit them. And if not 'legal' - then deny them without any 'time' limitations.

You can use a session field with a global variable holding the time of last ajax request. Since you want to allow 8 requests, make it an array of size 8 and check for the time differences. If it increases, (important) it might not always be a bot. give the user a chance with captcha or something similar. (a math problem maybe?)

once the captcha is validated, allow the next few posts etc..

But do make sure that you are checking for that particular session and user.

Kerin's answer is good, I just wanted to emphasize on captcha.

yes you need to use a function in every function views can interact, also, it should be in global library so you can use it anywhere.

if(is_logged_in())
{
    // do you code here 
}

while is_logged in is defined as follows

function is_logged_in($activated = TRUE)
{
    return $this->ci->session->userdata('status') === ($activated ? STATUS_ACTIVATED : STATUS_NOT_ACTIVATED);
}

you should set the status session when user login successfully.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM