Rate limiting for FeathersJS HTTP (REST API) and Web Sockets connections (Express, Node.js)
'use strict'
const bodyParser = require('body-parser')
const compress = require('compression')
const configuration = require('feathers-configuration')
const cors = require('cors')
const favicon = require('serve-favicon')
const feathers = require('feathers')
const hooks = require('feathers-hooks')
const limiter = require('limiter').RateLimiter // Generic limiter used for authentication attempts inside web socket connection
const middleware = require('./middleware')
const path = require('path')
const rateLimit = require('express-rate-limit') // Express middleware limiter used for HTTP requests
const rest = require('feathers-rest')
const serveStatic = require('feathers').static
const services = require('./services')
const socketio = require('feathers-socketio')
const app = feathers()
app.configure(configuration(path.join(__dirname, '..')))
const authLimiter = new rateLimit({
windowMs: 15*60*1000, // 15 minutes window
delayAfter: 1, // begin slowing down responses after the first request
delayMs: 3*1000, // slow down subsequent responses by 3 seconds per request
max: 5 // start blocking after 5 requests
})
app.use(compress())
.use('/auth/', authLimiter) // limit authentication attempts via REST API
.use('/socket.io/', authLimiter) // limit web socket connections
.options('*', cors())
.use(cors())
.use(favicon(path.join(app.get('public'), 'favicon.ico')))
.use('/', serveStatic(app.get('public')))
.use(bodyParser.json())
.use(bodyParser.urlencoded({ extended: true }))
.configure(hooks())
.configure(rest())
.configure(socketio(io => {
io.on('connection', socket => {
const socketLimiter = new limiter(1, 3000) // allow 1 authentication attempt every 3 seconds inside current web socket connection
socket.on('authenticate', () => {
if(!socketLimiter.tryRemoveTokens(1)) { // if exceeded, connection is dropped
console.log('Too many socket.io auth attempts from %s, disconnecting.', socket.conn.remoteAddress)
socket.send('Too many authentication attempts from you, disconnecting.')
socket.disconnect()
}
})
})
}))
.configure(services)
.configure(middleware)
module.exports = app