Skip to content

Instantly share code, notes, and snippets.

@kkkrist
Last active February 26, 2019 00:26
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save kkkrist/0462bbed6f7662a9414ca26bb2f74b64 to your computer and use it in GitHub Desktop.
Save kkkrist/0462bbed6f7662a9414ca26bb2f74b64 to your computer and use it in GitHub Desktop.
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment