Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rate limiting to prevent malicious behavior in ExpressJS

Someone made me aware of some flaws in an application I'm working on (mostly within my JavaScript on the front-end), that leaves open the possibility of, say, clicking a ton of buttons at once and sending out a ton of transactional emails. This is clearly not good.

I think one way to handle this in ExpressJS is by using app.all() to count the number of requests that happen within a certain timeframe. I'd store this in the session metadata with timestamps, and if more than X requests happen in Y time, I cut them off for awhile until the limit expires.

Has anyone done this before or have any tips/hints to help me out? Something that's easy to drop in and out of my app is preferable. Thanks!

like image 263
Josh Smith Avatar asked Feb 24 '12 02:02

Josh Smith


1 Answers

You could use the Collate object in your webpage.

function Collate(timeout) {
  this.timeout = timeout || 1000;
}
Collate.prototype = {
  time: 0,

  idle: function() {
    var t = new Date().getTime();
    return (t - this.time > this.timeout && (this.time = t));
  },

  prefer: function(func) {
    this.func = func;
    clearTimeout(this.timer);
    this.timer = setTimeout(func, this.timeout);
  }
};

If you want a function to run once and not run again within the next 1 second. Like if you want to prevent the user from submitting a form many times, you do this:

var timer = new Collate(3000);  //3 seconds
button1.onclick = function() {
    if(timer.idle()) {
        button1.form.submit();
    } else alert("Don't click too quickly!");
}

//or on the form tag

<script>var submitTimer = new Collate(3000);</script>
<form action="post" onsubmit="return submitTimer.idle();">

If you expect an event to fire multiple times and only want to react to the last time it fires. Like if you want to search after a user has finished typing, you do this:

var timer = new Collate(700); //0.7 seconds
textfield1.onkeyup = function() {
    timer.prefer(function() {
        autocomplete.search(textfield1.value);
    });
};
like image 94
Kernel James Avatar answered Oct 01 '22 12:10

Kernel James