request-throttler

2.0.0 • Public • Published

request-throttler

Middleware to throttle requests by a single use/set of users. Helpful in reducing server load, preventing datamining, and stifling brute force attacks.

If a given user goes above the allowed requestsPerSecond, a 503 is returned for every request until the average drops. User state and request count is kept int the redis database and reset after timeToLive seconds. The user request count is stored in a redis database, specified during configuration.

It's important to note that the count can only be updated as fast as the redis database allows access. if two requests come in at the same time, the count will only be increased by one.

Note: The --harmony flag is required for both koa and express

Key

Usage

koa

app.use(throttler.koa({
  port              : 6379,
  host              : 127.0.0.1,
  requestsPerSecond : 50,
  timeToLive        : 60,
  throttler         : function *() {
    console.log('I\'ve been throttled!');
    this.status = 503;
    this.body = 'Service unavailable'
  },
  error : function *(error) {
    console.log(error.stack);
    this.status = 500;
    this.body = 'Internal server error'  
  }
}));

express

app.use(throttler.express({
  port              : 6379,
  host              : 127.0.0.1,
  requestsPerSecond : 50,
  timeToLive        : 60,
  throttler         : function () {
    console.log('I\'ve been throttled!');
    res.status(503).send('Service unavailable');
  },
  error : function (error) {
    console.log(error.stack);
    res.status(500).send('Internal server error');
  }
}));

Duck type

// app is express or koa
 
throttler(app, {
  port              : 6379,
  host              : 127.0.0.1,
  requestsPerSecond : 50,
  timeToLive        : 60,
})

Configuration

config.host

  • Optional
  • The host where the redis database can be accessed
  • Default: 127.0.0.1
config.host = 127.0.0.1

config.port

  • Optional
  • The port where the redis database can be accessed
  • Default: 6379
config.port = 6379

config.requestsPerSecond

  • Required
  • The number of request per second allowed by a user
  • Make sure to base this on uniqueness of the fingerprint
config.requestsPerSecond = 30;

config.timeToLive

  • Required
  • The lifespan (in seconds) of the fingerprint store
  • Lower lifespan will cause faster fingerprint expiration and cut down on storage size
  • Higher lifespan will allow a users request to normalize over time (bursts will be less likely to throttle the user)
config.timeToLive = 60;

config.throttler

  • Optional
  • The handler called when a user is throttled
  • Default: sends a 503 and generic Service unavailable message
// express
config.throttler = function () {
  console.log('I\'ve been throttled!');
  res.status(503).send('Service unavailable');
}
 
//koa
config.throttler = function *(error) {
  console.log(error.stack);
  this.status = 500;
  this.body = 'Internal server error'  
}

config.error

  • Optional
  • The handler called if an error occurs
  • Default: sends a 500 and generic Internal server error message
// express
config.error = function (error) {
  console.log(error.stack);
  res.status(500).send('Internal server error');
}
 
//koa
config.error = function *(error) {
  console.log(error.stack);
  this.status = 500;
  this.body = 'Internal server error'  
}

Customization

Redis Workarounds

The redis store methods and be overridden, and redis can be removed entirely if desired. The following methods should be used

config.client

  • Must be an object with get(stringKey, callback) and set(stringKey, stringValue, callback)
config.client = {
  get: function (key, callback) {
    return yourGetOperation(key, function (error, result) {
      return callback(error, result);
    });
  },
  set: function (key, value, callback) {
    return yourSetOperation(key, value, function (error, result) {
      return callback(error, result);
    });
  }
}

config.getFingerprint

  • Generator function to get a fingerprint
config.getFingerprint = function *(key) {
  yield yourGetOperation(key);
}

config.setFingerprint

  • Generator function to set a fingerprint
config.setFingerprint = function *(key, newRequestCount) {
  yield yourSetOperation(key, newRequestCount);
}

Package Sidebar

Install

npm i request-throttler

Weekly Downloads

3

Version

2.0.0

License

MIT

Last publish

Collaborators

  • johnhof