block user ip in node js middleware

597 Views Asked by At

i want to use express-rate-limiter in a middleware of my node.js app. how can i? in a usuall app, it's in the server.js but i want to blcok user in a middleware.

thanks for your responses

const express=require('express');
const app=express();
const jwt = require("jsonwebtoken");

const rateLimit = require('express-rate-limit');
// limit user logins
const tokenLimiter = rateLimit({
    windowMs: 3 * 60 * 1000,
    max: 3,
    statusCode: 200,
    message: {
        status: 429,
        error: 'block msg'
    },
    handler: function (req, res) {
        res.status(429).json({ msg: 'block msg' });
    },
});

module.exports = function (req, res, next) {
    let token = req.cookies.authorization;
    if (!token) {
        token = req.headers.authorization;
    }
    if (!token) return res.status(401).json({ msg: 'please login' });
    try {
        const verified = jwt.verify(token, process.env.THE_TOKEN_SECRET);
        req.user = verified;
        next();
    } catch (e) {
        app.use(tokenLimiter);
        res.status(200).json({ router: "login" });
    }
};

2

There are 2 best solutions below

0
Naveen Kulkarni On

You shouldn't be doing this, this voilates the idea of rate limitter. Express executes middlewares sequentially.You should be calling your middleware right after the rate limiter in server.js. I would use something like below in my server.js

const rateLimit = require('express-rate-limit')
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
}) // Apply the rate limiting middleware to all requests
app.use(limiter)
app.use(secondMiddleware)

Or you could also chain them like Chaining multiple pieces of middleware for specific route in ExpressJS

But if you really want to do it, one workaround is in your code on catch you are redirecting to login, you can add the rate limitter just at login as a middleware.

0
Nathan Friedly On

express-rate-limit has a skipSuccessfulRequests option to only¹ count requests that result in an error. By default it looks at the status code, but you can customize it to look at other aspects via a custom requestWasSuccessful function:

const express=require('express');
const app=express();
const jwt = require("jsonwebtoken");

const rateLimit = require('express-rate-limit');
// limit failed logins
const tokenLimiter = rateLimit({
    windowMs: 3 * 60 * 1000,
    max: 3,
    statusCode: 200,
    message: {
        status: 429,
        error: 'block msg'
    },
    // note: a custom handler function will override the above statusCode and message settings
    // handler: function (req, res) {
    //     res.status(429).json({ msg: 'block msg' });
    // }, 
    skipSuccessfulRequests: true,
    requestWasSuccessful: function (req, res) {
      return !req.tokenVerificationFailed;
    },
});

function verifyToken(req, res, next) {
    let token = req.cookies.authorization;
    if (!token) {
        token = req.headers.authorization;
    }
    if (!token) return res.status(401).json({ msg: 'please login' });
    try {
        const verified = jwt.verify(token, process.env.THE_TOKEN_SECRET);
        req.user = verified;
        next();
    } catch (e) {
        res.tokenVerificationFailed = true;
        res.status(200).json({ router: "login" });
    }
};

app.use(tokenLimiter);
app.use(verifyToken);

(I also commented out your custom handler function since it would conflict with the statusCode and message configuration options.)

¹ Technically it counts all requests and then un-counts the successful ones, so a million requests at once would probably still be limited, even if they would ultimately all be successful otherwise.


For an alternative option, you could run verifyToken first, and then configure express-rate-limit with a custom skip function that skips any request with a req.user field. This would avoid the 'million requests at once' issue, but it would apply the limiter to unauthenticated users who just don't have any token, which doesn't appear to be your intention.


Disclosure: I'm the author of express-rate-limit.