• Stars
    star
    107
  • Rank 323,587 (Top 7 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 8 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

☔ Fast and efficient in-memory rate-limit for Node, used to alleviate most common DOS attacks.

node-fast-ratelimit

Test and Build Build and Release NPM Downloads Gitter Buy Me A Coffee

Fast and efficient in-memory rate-limit, used to alleviate most common DOS attacks.

This rate-limiter was designed to be as generic as possible, usable in any NodeJS project environment, regardless of whether you're using a framework or just vanilla code. It does not require any dependencies, making it lightweight to install and use.

🇫🇷 Crafted in Lannion, France.

Who uses it?

Crisp Doctrine Anchor.Chat WeStudents

👋 You use fast-ratelimit and you want to be listed there? Contact me.

How to install?

Include fast-ratelimit in your package.json dependencies.

Alternatively, you can run npm install fast-ratelimit --save.

TypeScript users can install type definitions by running npm install --save-dev @types/fast-ratelimit. Note that this is a third-party package, ie. not maintained by myself.

How to use?

The fast-ratelimit API is pretty simple, here are some keywords used in the docs:

  • ratelimiter: ratelimiter instance, which plays the role of limits storage
  • namespace: the master ratelimit storage namespace (eg: set namespace to the user client IP, or user username)

You can create as many ratelimiter instances as you need in your application. This is great if you need to rate-limit IPs on specific zones (eg: for a chat application, you don't want the message send rate limit to affect the message composing notification rate limit).

Here's how to proceed (we take the example of rate-limiting messages sending in a chat app):

1. Create the rate-limiter

The rate-limiter can be instanciated as such:

var FastRateLimit = require("fast-ratelimit").FastRateLimit;

var messageLimiter = new FastRateLimit({
  threshold : 20, // available tokens over timespan
  ttl       : 60  // time-to-live value of token bucket (in seconds)
});

This limiter will allow 20 messages to be sent every minute per namespace. An user can send a maximum number of 20 messages in a 1 minute timespan, with a token counter reset every minute for a given namespace.

The reset scheduling is done per-namespace; eg: if namespace user_1 sends 1 message at 11:00:32am, he will have 19 messages remaining from 11:00:32am to 11:01:32am. Hence, his limiter will reset at 11:01:32am, and won't scheduler any more reset until he consumes another token.

2. Check by consuming a token

On the message send portion of our application code, we would add a call to the ratelimiter instance.

2.1. Consume token with asynchronous API (Promise catch/reject)

// This would be dynamic in your application, based on user session data, or user IP
namespace = "user_1";

// Check if user is allowed to send message
messageLimiter.consume(namespace)
  .then(() => {
    // Consumed a token
    // Send message
    message.send();
  })
  .catch(() => {
    // No more token for namespace in current timespan
    // Silently discard message
  });

2.2. Consume token with synchronous API (boolean test)

// This would be dynamic in your application, based on user session data, or user IP
namespace = "user_1";

// Check if user is allowed to send message
if (messageLimiter.consumeSync(namespace) === true) {
  // Consumed a token
  // Send message
  message.send();
} else {
  // consumeSync returned false since there is no more tokens available
  // Silently discard message
}

3. Check without consuming a token

In some instances, like password brute forcing prevention, you may want to check without consuming a token and consume only when password validation fails.

3.1. Check whether there are remaining tokens with asynchronous API (Promise catch/reject)

limiter.hasToken(request.ip).then(() => {
  return authenticate(request.login, request.password)
})
  .then(
    () => {
      // User is authenticated
    },

    () => {
      // User is not authenticated
      // Consume a token and reject promise
      return limiter.consume(request.ip)
        .then(() => Promise.reject())
    }
  )
  .catch(() => {
    // Either invalid authentication or too many invalid login
    return response.unauthorized();
  })

3.2. Check whether there are remaining tokens with synchronous API (boolean test)

if (!limiter.hasTokenSync(request.ip)) {
  throw new Error("Too many invalid login");
}

const is_authenticated = authenticateSync(request.login, request.password);

if (!is_authenticated) {
  limiter.consumeSync(request.ip);

  throw new Error("Invalid login/password");
}

Notes on performance

This module is used extensively on edge WebSocket servers, handling thousands of connections every second with multiple rate limit lists on the top of each other. Everything works smoothly, I/O doesn't block and RAM didn't move that much with the rate-limiting module enabled.

On one core of a 2,3 GHz 8-Core Intel Core i9, the parallel asynchronous processing of 100,000 namespaces in the same limiter take an average of 160 ms, which is fine (1.6 microseconds per operation).

Why not using existing similar modules?

I was looking for an efficient, yet simple, DOS-prevention technique that wouldn't hurt performance and consume tons of memory. All proper modules I found were relying on Redis as the keystore for limits, which is definitely not great if you want to keep away from DOS attacks: using such a module under DOS conditions would subsequently DOS Redis since 1 (or more) Redis queries are made per limit check (1 attacker request = 1 limit check). Attacks should definitely not be allieviated this way, although a Redis-based solution would be perfect to limit abusing users.

This module keeps all limits in-memory, which is much better for our attack-prevention concern. The only downside: since the limits database isn't shared, limits are per-process. This means that you should only use this module to prevent hard-attacks at any level of your infrastructure. This works pretty well for micro-service infrastructures, which is what we're using it in.

More Repositories

1

sonic

🦔 Fast, lightweight & schema-less search backend. An alternative to Elasticsearch that runs on a few MBs of RAM.
Rust
19,769
star
2

vigil

🚦 Microservices Status Page. Monitors a distributed infrastructure and sends alerts (Slack, SMS, etc.).
Rust
1,690
star
3

bloom

🌸 HTTP REST API caching middleware, to be used between load balancers and REST API workers.
Rust
711
star
4

node-sales-tax

💰 International sales tax calculator for Node (offline, but provides optional online VAT number fraud check). Tax rates are kept up-to-date.
JavaScript
298
star
5

node-sonic-channel

🦉 Sonic Channel integration for Node. Used in pair with Sonic, the fast, lightweight and schema-less search backend.
JavaScript
145
star
6

raider

🐎 Affiliates dashboard. Used by affiliates to generate tracking codes and review their balance.
Rust
144
star
7

constellation

🌌 Pluggable authoritative DNS server. Entries can be added & removed from an HTTP REST API.
Rust
127
star
8

jquery.clipboard

✂️ jQuery Clipboard plugin (newest version) - Copy any text to the user's clipboard. Implements ZeroClipboard over the jQuery plugin layer.
JavaScript
70
star
9

giggle

📞 Giggle Jingle library for XMPP, implementation of XEP-0166.
JavaScript
57
star
10

vigil-local

🕯 Vigil Local daemon. Used as a slave service to monitor hosts behind a firewall and report their status to Vigil.
Rust
21
star
11

boulder-dash

:godmode: Boulder Dash game remake, done in Java.
Java
14
star
12

django-gitlab-logging

🍷 A logging handler for Django that opens GitLab issues on server error.
Python
13
star
13

plotters-conrod

📈 Conrod backend for Plotters. This is more efficient than using the default Bitmap backend when plotting in Conrod.
Rust
13
star
14

callisto

💫 Yet another Solar System simulator, written in Go.
Go
11
star
15

go-vigil-reporter

🚧 Vigil Reporter for Golang. Used in pair with Vigil, the Microservices Status Page.
Go
11
star
16

node-vigil-reporter

🚧 Vigil Reporter for Node. Used in pair with Vigil, the Microservices Status Page.
JavaScript
10
star
17

gulp-remove-logging

🚿 Removes console logging statements.
JavaScript
8
star
18

rs-vigil-reporter

🚧 Vigil Reporter for Rust. Used in pair with Vigil, the Microservices Status Page.
Rust
7
star
19

progressio

🎈 Beautiful & stylish asynchronous page loader. Makes a static website dynamic in a breeze.
JavaScript
7
star
20

node-gitlab-logging

🍺 A logging handler for NodeJS that opens GitLab issues on provided exception.
JavaScript
7
star
21

node-bloom-control

💐 Bloom Control integration for Node. Used in pair with Bloom, the HTTP REST API caching middleware.
JavaScript
7
star
22

grunt-blurred-images

🔮 Produce blurred versions of images. Used to reproduce Medium blur-on-scroll effect.
JavaScript
5
star
23

django-request-mock

🙈 Create a Django request object that mocks a real one. Useful in case a real request object is not available, but is needed (delayed Celery tasks for instance)
Python
5
star
24

waaave-bootstrap

🏄 The Waaave Bootstrap. Efficient by design.
JavaScript
4
star
25

waaave-web

🏄 Waaave, The Developer Sharing Network. Tutorials, Shots and more.
Python
4
star
26

lab-iot-homekit

💡 HomeKit-powered home automation IoT projects, running on ESP32.
C
3
star
27

node-spamassassin-client

🔪 SpamAssassin client for Node. Lets you check if an email is spam or ham.
JavaScript
3
star
28

grunt-contrib-lualint

💊 Grunt task for validating Lua code.
Lua
2
star
29

server-workflow-scripts

🐹 Server workflow scripts for fast project deployment and execution - used with valeriansaliou/gitlab-deploy-hooks
Shell
2
star
30

datastore.js

🐘 A complete Web storage wrapper (sessionStorage/localStorage). Provides a fallback when not supported.
JavaScript
2
star
31

jquery.hasparent

💡 jQuery hasParent helper. Checks if the selected element has a defined parent element.
JavaScript
2
star
32

medius

🍊 Learn how the immune system works with Medius, a real-time fight game.
Python
2
star
33

gulp-jade-client

🐰 Compiles Jade templates from the browser.
JavaScript
1
star
34

waaave-hitcount

🏄 Basic app that allows you to track the number of hits/views for a particular object.
Python
1
star
35

valeriansaliou

👱🏻‍♂️ My GitHub profile.
1
star
36

backlinks-manager

🎃 BackLinks.com ads manager. Easily deploy a BackLinks.com ad code, with a fast cache system.
PHP
1
star
37

lab-eigenfaces

💡 Face recognition algorithm implementation, using the eigenfaces technique.
MATLAB
1
star
38

grunt-contrib-rubylint

💊 Grunt task for validating Ruby code.
JavaScript
1
star
39

dns-deploy-utilities

🐬 Utilities to deploy DNS configurations for the BIND9 nameserver.
1
star