Search code examples
node.jsjsonexpresspostlimit

Node.js: express.json limit whitelist


I have a Node.js backend with many routes which have nothing to do with uploading files (for regular users, therefore a limit of 50kb). But I want to have a few routes for only admins that can upload files, therefore I want a higher express.json and express.urlencoded limit (10MB). I would use router.use in a routes file but some extra middleware needs the express.json and express.urlencoded. Here's my current code:

const express = require("express");
const app = express();
...
app.use(express.json({ limit: '50kb' }));
app.use(express.urlencoded({ limit: '50kb', extended: true }));
!!! Some middlewares that need the json and urlencoded middleware !!!
...
app.use("/api/account", accountRoutes);
app.use("/api/users", usersRoutes);
app.use("/api/news", newsRoutes);
app.use("/api/admin", adminRoutes); // I want a higher limit for this route
...

Each Routes file exports a express.Router()

Is there some kind of whitelisting? Could I make a middleware myself with a whitelist?


Solution

  • You can just rate-limit per individual routers. Here's a trivial example (note that I set the global limit after the individual route limits, that is important):

    const app = express();
    
    // one specific route
    const onekbRouter = express.Router()
    onekbRouter.use(express.json({ limit: '400b' }))
    onekbRouter.post('/', (_, res) => res.send('okay buddy'))
    
    // another route
    const oneMbRouter = express.Router()
    oneMbRouter.use(express.json({ limit: '1Mb' }))
    oneMbRouter.post('/', (_, res) => res.send('okay buddy'))
    
    app.use('/1kb', onekbRouter)
    app.use('/1Mb', oneMbRouter)
    
    // global limit
    app.use(express.json({ limit: '1kb' }))
    
    app.get('/', (_, res) => res.send('<a href="/1kb">1kb</a> <a href="/1mb">1Mb</a>'))
    
    app.listen(3000, () => console.log('Go get\'em'))
    
    module.exports = app
    

    Testing this works properly for me. 3 requests return "okay buddy", 1 fails here:

    okay buddy[zlatko@dilj ~/tmp/new]$ curl -d @1kb.json http://localhost:3000/1kb -X POST -H "content-type: application/json"
    okay buddy[zlatko@dilj ~/tmp/new]$ curl -d @1kb.json http://localhost:3000/1mb -X POST -H "content-type: application/json"
    okay buddy[zlatko@dilj ~/tmp/new]$ curl -d @1mb.json http://localhost:3000/1mb -X POST -H "content-type: application/json"
    okay buddy[zlatko@dilj ~/tmp/new]$ curl -d @1mb.json http://localhost:3000/1kb -X POST -H "content-type: application/json"
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="utf-8">
    <title>Error</title>
    </head>
    <body>
    <pre>PayloadTooLargeError: request entity too large<br> &nbsp; &nbsp;at readStream (/home/zlatko/tmp/new/node_modules/raw-body/index.js:155:17)<br> &nbsp; &nbsp;at getRawBody (/home/zlatko/tmp/new/node_modules/raw-body/index.js:108:12)<br> &nbsp; &nbsp;at read (/home/zlatko/tmp/new/node_modules/body-parser/lib/read.js:77:3)<br> &nbsp; &nbsp;at jsonParser (/home/zlatko/tmp/new/node_modules/body-parser/lib/types/json.js:135:5)<br> &nbsp; &nbsp;at Layer.handle [as handle_request] (/home/zlatko/tmp/new/node_modules/express/lib/router/layer.js:95:5)<br> &nbsp; &nbsp;at trim_prefix (/home/zlatko/tmp/new/node_modules/express/lib/router/index.js:317:13)<br> &nbsp; &nbsp;at /home/zlatko/tmp/new/node_modules/express/lib/router/index.js:284:7<br> &nbsp; &nbsp;at Function.process_params (/home/zlatko/tmp/new/node_modules/express/lib/router/index.js:335:12)<br> &nbsp; &nbsp;at next (/home/zlatko/tmp/new/node_modules/express/lib/router/index.js:275:10)<br> &nbsp; &nbsp;at Function.handle (/home/zlatko/tmp/new/node_modules/express/lib/router/index.js:174:3)</pre>
    </body>
    </html>
    [zlatko@dilj ~/tmp/new]$
    

    The sizes are not there, but are around the limits:

    $ ls -hl 1*json
    -rw-r--r--. 1 zlatko zlatko  28 Aug  5 15:23 1kb.json
    -rw-r--r--. 1 zlatko zlatko 14K Aug  5 15:26 1mb.json