Last active
February 26, 2019 00:26
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'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