From 7f72a481ea1e8776e98fe2fd9f56e7e59675a196 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Wed, 30 Nov 2016 10:53:33 -0300 Subject: [PATCH 1/3] add rate limitation to createWallet --- README.md | 2 ++ lib/common/defaults.js | 14 ++++++++++++++ lib/expressapp.js | 13 ++++++++++++- package.json | 26 ++++++++++++++++---------- 4 files changed, 44 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 89ace73..268580f 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,8 @@ BWS needs mongoDB. You can configure the connection at `config.js` BWS supports SSL and Clustering. For a detailed guide on installing BWS with extra features see [Installing BWS](https://github.com/bitpay/bitcore-wallet-service/blob/master/installation.md). +BWS uses by default a Request Rate Limitation to CreateWallet endpoint. If you need to modify it, check defaults.js' `Defaults.RateLimit` + # Security Considerations * Private keys are never sent to BWS. Copayers store them locally. * Extended public keys are stored on BWS. This allows BWS to easily check wallet balance, send offline notifications to copayers, etc. diff --git a/lib/common/defaults.js b/lib/common/defaults.js index b0e299a..35c8933 100644 --- a/lib/common/defaults.js +++ b/lib/common/defaults.js @@ -90,4 +90,18 @@ Defaults.NOTIFICATIONS_TIMESPAN = 60; Defaults.SESSION_EXPIRATION = 1 * 60 * 60; // 1 hour to session expiration +Defaults.RateLimit = { + createWallet: { + windowMs: 60 * 60 * 1000, // hour window + delayAfter: 5, // begin slowing down responses after the 3rd request + delayMs: 3 * 1000, // slow down subsequent responses by 3 seconds per request + max: 20, // start blocking after 20 requests + message: "Too many accounts created from this IP, please try again after an hour" + }, + // otherPosts: { + // windowMs: 60 * 60 * 1000, // 1 hour window + // max: 1200 , // 1 post every 3 sec average, max. + // }, +}; + module.exports = Defaults; diff --git a/lib/expressapp.js b/lib/expressapp.js index 1c50e53..640c817 100644 --- a/lib/expressapp.js +++ b/lib/expressapp.js @@ -7,6 +7,7 @@ var log = require('npmlog'); var express = require('express'); var bodyParser = require('body-parser'); var compression = require('compression'); +var RateLimit = require('express-rate-limit'); var Common = require('./common'); var Defaults = Common.Defaults; @@ -81,9 +82,9 @@ ExpressApp.prototype.start = function(opts, cb) { this.app.use(morgan(logFormat, logOpts)); } - var router = express.Router(); + function returnError(err, res, req) { if (err instanceof WalletService.ClientError) { @@ -169,7 +170,17 @@ ExpressApp.prototype.start = function(opts, cb) { }); }; + + + if (Defaults.RateLimit.createWallet) { + log.info('', 'Limiting wallet creation per IP: %d req/h', (Defaults.RateLimit.createWallet.max / Defaults.RateLimit.createWallet.windowMs * 60 * 60 * 1000).toFixed(2)) + var createWalletLimiter = new RateLimit(Defaults.RateLimit.createWallet); + router.use('/v1/wallets/', createWalletLimiter) + router.use('/v2/wallets/', createWalletLimiter) + } + // DEPRECATED + router.post('/v1/wallets/', function(req, res) { logDeprecated(req); var server; diff --git a/package.json b/package.json index e719bc0..25834b4 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "description": "A service for Mutisig HD Bitcoin Wallets", "author": "BitPay Inc", "version": "1.13.0", + "licence": "MIT", "keywords": [ "bitcoin", "copay", @@ -26,6 +27,7 @@ "coveralls": "^2.11.2", "email-validator": "^1.0.1", "express": "^4.10.0", + "express-rate-limit": "^2.6.0", "inherits": "^2.0.1", "json-stable-stringify": "^1.0.0", "locker": "^0.1.0", @@ -68,14 +70,18 @@ "coveralls": "./node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage" }, "bitcoreNode": "./bitcorenode", - "contributors": [{ - "name": "Braydon Fuller", - "email": "braydon@bitpay.com" - }, { - "name": "Ivan Socolsky", - "email": "ivan@bitpay.com" - }, { - "name": "Matias Alejo Garcia", - "email": "ematiu@gmail.com" - }] + "contributors": [ + { + "name": "Braydon Fuller", + "email": "braydon@bitpay.com" + }, + { + "name": "Ivan Socolsky", + "email": "ivan@bitpay.com" + }, + { + "name": "Matias Alejo Garcia", + "email": "ematiu@gmail.com" + } + ] } From 711f9516e5c5ec9a06bcfa3cc4d333987ec0f2a7 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Wed, 30 Nov 2016 11:16:29 -0300 Subject: [PATCH 2/3] fix endpoint matching --- lib/common/defaults.js | 8 ++++---- lib/expressapp.js | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/common/defaults.js b/lib/common/defaults.js index 35c8933..253de27 100644 --- a/lib/common/defaults.js +++ b/lib/common/defaults.js @@ -93,10 +93,10 @@ Defaults.SESSION_EXPIRATION = 1 * 60 * 60; // 1 hour to session expiration Defaults.RateLimit = { createWallet: { windowMs: 60 * 60 * 1000, // hour window - delayAfter: 5, // begin slowing down responses after the 3rd request - delayMs: 3 * 1000, // slow down subsequent responses by 3 seconds per request - max: 20, // start blocking after 20 requests - message: "Too many accounts created from this IP, please try again after an hour" + delayAfter: 10, // begin slowing down responses after the 3rd request + delayMs: 3000, // slow down subsequent responses by 3 seconds per request + max: 20, // start blocking after 20 request + message: "Too many wallets created from this IP, please try again after an hour" }, // otherPosts: { // windowMs: 60 * 60 * 1000, // 1 hour window diff --git a/lib/expressapp.js b/lib/expressapp.js index 640c817..f0233ed 100644 --- a/lib/expressapp.js +++ b/lib/expressapp.js @@ -175,8 +175,8 @@ ExpressApp.prototype.start = function(opts, cb) { if (Defaults.RateLimit.createWallet) { log.info('', 'Limiting wallet creation per IP: %d req/h', (Defaults.RateLimit.createWallet.max / Defaults.RateLimit.createWallet.windowMs * 60 * 60 * 1000).toFixed(2)) var createWalletLimiter = new RateLimit(Defaults.RateLimit.createWallet); - router.use('/v1/wallets/', createWalletLimiter) - router.use('/v2/wallets/', createWalletLimiter) + router.use(/\v1\/wallets\/$/, createWalletLimiter) + router.use(/\/v2\/wallets\/$/, createWalletLimiter) } // DEPRECATED From d8c786df79e5f5e4d0184a3972232655d765d127 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Wed, 30 Nov 2016 13:01:53 -0300 Subject: [PATCH 3/3] better reg --- lib/expressapp.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/expressapp.js b/lib/expressapp.js index f0233ed..2896b1c 100644 --- a/lib/expressapp.js +++ b/lib/expressapp.js @@ -175,8 +175,7 @@ ExpressApp.prototype.start = function(opts, cb) { if (Defaults.RateLimit.createWallet) { log.info('', 'Limiting wallet creation per IP: %d req/h', (Defaults.RateLimit.createWallet.max / Defaults.RateLimit.createWallet.windowMs * 60 * 60 * 1000).toFixed(2)) var createWalletLimiter = new RateLimit(Defaults.RateLimit.createWallet); - router.use(/\v1\/wallets\/$/, createWalletLimiter) - router.use(/\/v2\/wallets\/$/, createWalletLimiter) + router.use(/\/v\d+\/wallets\/$/, createWalletLimiter) } // DEPRECATED