express-rate-limit not working when deployed to heroku

Viewed 2006

I have this code working on localhost (sending has no problem only the express-rate-limit), but when I deploy / push it to my heroku app and do a post request it exceeds the max limit which is 3.

const router = require('express').Router();
const nodemailer = require('nodemailer');
const rateLimit = require("express-rate-limit");

const apiLimit = rateLimit({
    windowMs: 24 * 60 * 60 * 1000, // 24 hrs
    max: 3, // limit each IP to 3 requests per windowMs
    message: "Spam detected!"
});

router.route('/').post(apiLimit,(req, res) => {

    const transport = nodemailer.createTransport({
        service: 'gmail',
        host : "smtp.gmail.com",
        port : "465",
        ssl : true,
        auth: {
        user: process.env.USER,
        pass: process.env.PASS
    }
    });

    const mailOptions = {
        from: '',
        to: '<myemail>',
        subject: req.body.subject,
        text: "FROM: "+ req.body.email + " MESSAGE: " + req.body.message
    };

    transport.sendMail(mailOptions, (err, info) => {
        err ? res.json(res.status(400).json("Error " + err)) : res.json("Email sent.");
    });

});

module.exports = router ;

serving on localhost works, when i request more than 3x it returns the spam detected message and doesnt send mail anymore. when i use rest api extension on vscode this shows. The X-Ratelimit-Remaining: 2 doesnt change if i do a few more post requests.

HTTP/1.1 200 OK
Server: Cowboy
Connection: close
X-Powered-By: Express
Access-Control-Allow-Origin: *
X-Ratelimit-Limit: 3
X-Ratelimit-Remaining: 2
Date: Sun, 21 Jun 2020 03:09:11 GMT
X-Ratelimit-Reset: 1592793933
Content-Type: application/json; charset=utf-8
Content-Length: 13
Etag: W/"d-EBrE0f9LbjD0DZTwvOVLMa8Lqo8"
Via: 1.1 vegur

"Email sent."
1 Answers

It seems likely that the express-rate-limit module is not getting the correct IP address for the client when you run it on heroku? Perhaps because heroku is using a proxy in front of your server?

Per the express-rate-limit documentation:

// Enable if you're behind a reverse proxy (Heroku, Bluemix, AWS ELB, Nginx, etc)
// see https://expressjs.com/en/guide/behind-proxies.html
// app.set('trust proxy', 1);

So, it looks like perhaps you need:

app.set('trust proxy', 1);

This will cause the req.ip and req.ips values to be populated with the list of addresses from X-Forwarded-For header which is likely what express-rate-limiter needs when running behind a proxy.

Related