1
0
mirror of https://github.com/verdaccio/verdaccio.git synced 2024-12-24 21:15:51 +01:00

feat: add rate limit to all request (#2050)

* feat: add rate limit to all request

* chore: increase max

* chore: update settings

* chore: deprecate keepAliveTimeout
This commit is contained in:
Juan Picado 2021-01-09 07:16:41 +01:00
parent a78ff7550a
commit b61f762d6c
8 changed files with 91 additions and 3 deletions

@ -0,0 +1,51 @@
---
'@verdaccio/api': minor
'@verdaccio/auth': minor
'@verdaccio/cli': minor
'@verdaccio/config': minor
'@verdaccio/commons-api': minor
'@verdaccio/file-locking': minor
'verdaccio-htpasswd': minor
'@verdaccio/local-storage': minor
'@verdaccio/readme': minor
'@verdaccio/streams': minor
'@verdaccio/types': minor
'@verdaccio/hooks': minor
'@verdaccio/loaders': minor
'@verdaccio/logger': minor
'@verdaccio/logger-prettify': minor
'@verdaccio/middleware': minor
'@verdaccio/mock': minor
'@verdaccio/node-api': minor
'@verdaccio/active-directory': minor
'verdaccio-audit': minor
'verdaccio-auth-memory': minor
'verdaccio-aws-s3-storage': minor
'verdaccio-google-cloud': minor
'verdaccio-memory': minor
'@verdaccio/ui-theme': minor
'@verdaccio/proxy': minor
'@verdaccio/server': minor
'@verdaccio/store': minor
'@verdaccio/dev-types': minor
'@verdaccio/utils': minor
'verdaccio': minor
'@verdaccio/web': minor
---
feat: add server rate limit protection to all request
To modify custom values, use the server settings property.
```markdown
server:
## https://www.npmjs.com/package/express-rate-limit#configuration-options
rateLimit:
windowMs: 1000
max: 10000
```
The values are intended to be high, if you want to improve security of your server consider
using different values.

@ -63,11 +63,12 @@ packages:
# if package is not available locally, proxy requests to 'npmjs' registry # if package is not available locally, proxy requests to 'npmjs' registry
proxy: npmjs proxy: npmjs
# You can specify HTTP/1.1 server keep alive timeout in seconds for incoming connections.
# A value of 0 makes the http server behave similarly to Node.js versions prior to 8.0.0, which did not have a keep-alive timeout.
# WORKAROUND: Through given configuration you can workaround following issue https://github.com/verdaccio/verdaccio/issues/301. Set to 0 in case 60 is not enough.
server: server:
# deprecated
keepAliveTimeout: 60 keepAliveTimeout: 60
# rateLimit:
# windowMs: 1000
# max: 10000
middlewares: middlewares:
audit: audit:

@ -10,6 +10,7 @@ import {
ConfigRuntime, ConfigRuntime,
Security, Security,
PackageAccess, PackageAccess,
ServerSettingsConf,
AuthConf, AuthConf,
} from '@verdaccio/types'; } from '@verdaccio/types';
@ -18,6 +19,7 @@ import { getMatchedPackagesSpec, normalisePackageAccess } from './package-access
import { sanityCheckUplinksProps, uplinkSanityCheck } from './uplinks'; import { sanityCheckUplinksProps, uplinkSanityCheck } from './uplinks';
import { defaultSecurity } from './security'; import { defaultSecurity } from './security';
import { getUserAgent } from './agent'; import { getUserAgent } from './agent';
import serverSettings from './serverSettings';
const strategicConfigProps = ['uplinks', 'packages']; const strategicConfigProps = ['uplinks', 'packages'];
const allowedEnvConfig = ['http_proxy', 'https_proxy', 'no_proxy']; const allowedEnvConfig = ['http_proxy', 'https_proxy', 'no_proxy'];
@ -42,6 +44,7 @@ class Config implements AppConfig {
public storage: string | void; public storage: string | void;
public plugins: string | void; public plugins: string | void;
public security: Security; public security: Security;
public serverSettings: ServerSettingsConf;
// @ts-ignore // @ts-ignore
public secret: string; public secret: string;
@ -51,6 +54,7 @@ class Config implements AppConfig {
this.config_path = config.config_path; this.config_path = config.config_path;
this.plugins = config.plugins; this.plugins = config.plugins;
this.security = _.merge(defaultSecurity, config.security); this.security = _.merge(defaultSecurity, config.security);
this.serverSettings = serverSettings;
for (const configProp in config) { for (const configProp in config) {
if (self[configProp] == null) { if (self[configProp] == null) {

@ -0,0 +1,10 @@
export default {
// https://www.npmjs.com/package/express-rate-limit
// values are intended to be high, please customize based on own needs
rateLimit: {
windowMs: 1000,
max: 10000,
},
// deprecated
keepAliveTimeout: 60,
};

@ -336,6 +336,17 @@ declare module '@verdaccio/types' {
token?: boolean; token?: boolean;
search?: boolean; search?: boolean;
} }
export type RateLimit = {
windowMs: number;
max: number;
};
export type ServerSettingsConf = {
// express-rate-limit settings
rateLimit: RateLimit;
// deprecated
keepAliveTimeout?: number;
};
interface ConfigYaml { interface ConfigYaml {
_debug?: boolean; _debug?: boolean;
@ -360,6 +371,7 @@ declare module '@verdaccio/types' {
middlewares?: any; middlewares?: any;
filters?: any; filters?: any;
url_prefix?: string; url_prefix?: string;
server?: ServerSettingsConf;
flags?: ConfigFlags; flags?: ConfigFlags;
} }

@ -27,6 +27,7 @@
"@verdaccio/web": "workspace:5.0.0-alpha.2", "@verdaccio/web": "workspace:5.0.0-alpha.2",
"compression": "1.7.4", "compression": "1.7.4",
"cors": "2.8.5", "cors": "2.8.5",
"express-rate-limit": "5.2.3",
"express": "4.17.1", "express": "4.17.1",
"lodash": "4.17.15" "lodash": "4.17.15"
}, },

@ -2,6 +2,7 @@ import _ from 'lodash';
import express, { Application } from 'express'; import express, { Application } from 'express';
import compression from 'compression'; import compression from 'compression';
import cors from 'cors'; import cors from 'cors';
import RateLimit from 'express-rate-limit';
import { HttpError } from 'http-errors'; import { HttpError } from 'http-errors';
import { Storage } from '@verdaccio/store'; import { Storage } from '@verdaccio/store';
@ -36,10 +37,12 @@ interface IPluginMiddleware<T> extends IPlugin<T> {
const defineAPI = function (config: IConfig, storage: IStorageHandler): any { const defineAPI = function (config: IConfig, storage: IStorageHandler): any {
const auth: IAuth = new Auth(config); const auth: IAuth = new Auth(config);
const app: Application = express(); const app: Application = express();
const limiter = new RateLimit(config.serverSettings.rateLimit);
// run in production mode by default, just in case // run in production mode by default, just in case
// it shouldn't make any difference anyway // it shouldn't make any difference anyway
app.set('env', process.env.NODE_ENV || 'production'); app.set('env', process.env.NODE_ENV || 'production');
app.use(cors()); app.use(cors());
app.use(limiter);
// Router setup // Router setup
app.use(log(config)); app.use(log(config));

6
pnpm-lock.yaml generated

@ -828,6 +828,7 @@ importers:
compression: 1.7.4 compression: 1.7.4
cors: 2.8.5 cors: 2.8.5
express: 4.17.1 express: 4.17.1
express-rate-limit: 5.2.3
lodash: 4.17.15 lodash: 4.17.15
devDependencies: devDependencies:
'@verdaccio/mock': 'link:../mock' '@verdaccio/mock': 'link:../mock'
@ -850,6 +851,7 @@ importers:
compression: 1.7.4 compression: 1.7.4
cors: 2.8.5 cors: 2.8.5
express: 4.17.1 express: 4.17.1
express-rate-limit: 5.2.3
http-errors: 1.7.3 http-errors: 1.7.3
lodash: 4.17.15 lodash: 4.17.15
request: 2.87.0 request: 2.87.0
@ -12765,6 +12767,10 @@ packages:
graphql: ^14.4.1 graphql: ^14.4.1
resolution: resolution:
integrity: sha512-wccd9Lb6oeJ8yHpUs/8LcnGjFUUQYmOG9A5BNLybRdCzGw0PeUrtBxsIR8bfiur6uSW4OvPkVDoYH06z6/N9+w== integrity: sha512-wccd9Lb6oeJ8yHpUs/8LcnGjFUUQYmOG9A5BNLybRdCzGw0PeUrtBxsIR8bfiur6uSW4OvPkVDoYH06z6/N9+w==
/express-rate-limit/5.2.3:
dev: false
resolution:
integrity: sha512-cjQH+oDrEPXxc569XvxhHC6QXqJiuBT6BhZ70X3bdAImcnHnTNMVuMAJaT0TXPoRiEErUrVPRcOTpZpM36VbOQ==
/express/4.17.1: /express/4.17.1:
dependencies: dependencies:
accepts: 1.3.7 accepts: 1.3.7