Search code examples
javascriptspam-prevention

JavaScript anti-flood spam protection?


I was wondering if it were possible to implement some kind of crude JavaScript anti-flood protection. My code receives events from a server through AJAX, but sometimes these events can be quite frequent (they're not governed by me).

I have attempted to come up with a method of combating this, and I've written a small script: http://jsfiddle.net/Ry5k9/

var puts = {};

function receiverFunction(id, text) {
       if ( !puts[id] ) {
           puts = {};
           puts[id] = {};
       }

       puts[id].start = puts[id].start || new Date();
       var count = puts[id].count = puts[id].count + 1 || 0;
       var time = (new Date() - puts[id].start) * 0.001;

       $("text").set("text", (count / time.toFixed()).toString() + " lines/second");

       doSomethingWithTextIfNotSpam(text);
   }
};

which I think could prove effective against these kinds of attacks, but I'm wondering if it can be improved or perhaps rewritten?

So far, I think everything more than 3 or 2.5 lines per second seems like spam, but as time progresses forward (because start mark was set... well... at the start), an offender could simply idle for a while and then commence the flood, effectively never passing 1 line per minute.

Also, I would like to add that I use Mootools and Lo-Dash libraries (maybe they provide some interesting methods), but it would be preferable if this can be done using native JS.

Any insight is greatly appreciated!


Solution

  • I've spent many days pondering on effective measures to forbid message-flooding, until I came across the solution implemented somewhere else.

    First, we need three things, penalty and score variables, and a point in time where last action occured:

    var score = 0;
    var penalty = 200; // Penalty can be fine-tuned.
    var lastact = new Date();
    

    Next, we decrease score by the distance between the previous message and current in time.

    /* The smaller the distance, more time has to pass in order
     * to negate the score penalty cause{d,s}.
     */
    score -= (new Date() - lastact) * 0.05; 
    
    // Score shouldn't be less than zero.
    score = (score < 0) ? 0 : score;
    

    Then we add the message penalty and check if it crosses the threshold:

    if ( (score += penalty) > 1000 ) {
       // Do things.
    }
    

    Shouldn't forget to update last action afterwards:

    lastact = new Date();