From 98d64184d44eb150c381c87859f7b0342a04da7b Mon Sep 17 00:00:00 2001 From: dead-horse Date: Mon, 26 Mar 2018 14:22:56 +0800 Subject: [PATCH 1/3] feat: support safeCurl for SSRF protection --- README.md | 29 ++++++ agent.js | 7 ++ app.js | 3 + app/extend/agent.js | 19 ++++ app/extend/application.js | 16 +++ app/extend/context.js | 16 +++ config/config.default.js | 5 + lib/utils.js | 22 +++++ .../config/config.default.js | 14 +++ .../apps/ssrf-check-address/package.json | 3 + .../config/config.default.js | 11 +++ .../apps/ssrf-ip-black-list/package.json | 3 + test/ssrf.test.js | 98 +++++++++++++++++++ 13 files changed, 246 insertions(+) create mode 100644 agent.js create mode 100644 app/extend/agent.js create mode 100644 test/fixtures/apps/ssrf-check-address/config/config.default.js create mode 100644 test/fixtures/apps/ssrf-check-address/package.json create mode 100644 test/fixtures/apps/ssrf-ip-black-list/config/config.default.js create mode 100644 test/fixtures/apps/ssrf-ip-black-list/package.json create mode 100644 test/ssrf.test.js diff --git a/README.md b/README.md index 2f41f24..7bf891c 100644 --- a/README.md +++ b/README.md @@ -483,6 +483,35 @@ Defaulting to "SAMEORIGIN", only allow iframe embed by same origin. - disable Defaulting to `false`,same as `1; mode=block`. +### SSRF Protection + +In a [Server-Side Request Forgery (SSRF)]((https://www.owasp.org/index.php/Server_Side_Request_Forgery)) attack, the attacker can abuse functionality on the server to read or update internal resources. + +`egg-security` provide `ctx.safeCurl`, `app.safeCurl` and `agent.safeCurl` to provide http request(like `ctx.curl`, `app.curl` and `agent.curl`) with SSRF protection. + +#### Configuration + +* ipBlackList(Array) - specific which ip are illegal when request with `safeCurl`. +* checkAddress(Function) - determine the ip by the function's return value, `false` means illegal ip. + +```js +// config/config.default.js +exports.security = { + ssrf: { + // support both cidr subnet or specific ip + ipBlackList: [ + '10.0.0.0/8', + '127.0.0.1', + '0.0.0.0/32', + ], + // checkAddress has higher priority than ipBlackList + checkAddress(ip) { + return ip !== '127.0.0.1'; + } + }, +}; +``` + ## Other * Forbidden `trace` `track` `options` http method. diff --git a/agent.js b/agent.js new file mode 100644 index 0000000..18b2f9f --- /dev/null +++ b/agent.js @@ -0,0 +1,7 @@ +'use strict'; + +const utils = require('./lib/utils'); + +module.exports = agent => { + utils.processSSRFConfig(agent.config.security.ssrf); +}; diff --git a/app.js b/app.js index 3195d41..34941ab 100644 --- a/app.js +++ b/app.js @@ -1,10 +1,13 @@ 'use strict'; const safeRedirect = require('./lib/safe_redirect'); +const utils = require('./lib/utils'); module.exports = app => { app.config.coreMiddleware.push('securities'); // patch response.redirect safeRedirect(app); + + utils.processSSRFConfig(app.config.security.ssrf); }; diff --git a/app/extend/agent.js b/app/extend/agent.js new file mode 100644 index 0000000..c6edbe5 --- /dev/null +++ b/app/extend/agent.js @@ -0,0 +1,19 @@ +'use strict'; + +module.exports = { + /** + * safe curl with ssrf protect + * @param {String} url request url + * @param {Object} options request options + * @return {Promise} response + */ + safeCurl(url, options = {}) { + if (this.config.security.ssrf && this.config.security.ssrf.checkAddress) { + options.checkAddress = this.config.security.ssrf.checkAddress; + } else { + this.logger.warn('[egg-security] please configure `config.security.ssrf` first'); + } + + return this.curl(url, options); + }, +}; diff --git a/app/extend/application.js b/app/extend/application.js index 63ccdf7..36b30ba 100644 --- a/app/extend/application.js +++ b/app/extend/application.js @@ -30,3 +30,19 @@ const INJECTION_DEFENSE = '