@eggjs/security 4.0.1 → 5.0.0-beta.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (252) hide show
  1. package/README.md +46 -66
  2. package/README.zh-CN.md +56 -68
  3. package/dist/agent.d.ts +10 -0
  4. package/dist/agent.js +15 -0
  5. package/dist/app/extend/agent.d.ts +14 -0
  6. package/dist/app/extend/agent.js +12 -0
  7. package/dist/app/extend/application.d.ts +20 -0
  8. package/dist/app/extend/application.js +32 -0
  9. package/dist/app/extend/context.d.ts +74 -0
  10. package/dist/app/extend/context.js +191 -0
  11. package/dist/app/extend/helper.d.ts +24 -0
  12. package/dist/app/extend/helper.js +7 -0
  13. package/dist/app/extend/response.d.ts +45 -0
  14. package/dist/app/extend/response.js +70 -0
  15. package/dist/app/middleware/securities.d.ts +8 -0
  16. package/dist/app/middleware/securities.js +39 -0
  17. package/dist/app.d.ts +10 -0
  18. package/dist/app.js +24 -0
  19. package/dist/config/config.default.d.ts +874 -0
  20. package/dist/config/config.default.js +170 -0
  21. package/dist/config/config.local.d.ts +6 -0
  22. package/dist/config/config.local.js +5 -0
  23. package/dist/index.d.ts +1 -0
  24. package/dist/index.js +3 -0
  25. package/dist/lib/extend/safe_curl.d.ts +20 -0
  26. package/dist/lib/extend/safe_curl.js +19 -0
  27. package/dist/lib/helper/cliFilter.d.ts +7 -0
  28. package/dist/lib/helper/cliFilter.js +18 -0
  29. package/dist/lib/helper/escape.d.ts +2 -0
  30. package/dist/lib/helper/escape.js +7 -0
  31. package/dist/lib/helper/escapeShellArg.d.ts +4 -0
  32. package/dist/lib/helper/escapeShellArg.js +7 -0
  33. package/dist/lib/helper/escapeShellCmd.d.ts +4 -0
  34. package/dist/lib/helper/escapeShellCmd.js +15 -0
  35. package/dist/lib/helper/index.d.ts +24 -0
  36. package/dist/lib/helper/index.js +25 -0
  37. package/dist/lib/helper/shtml.d.ts +6 -0
  38. package/dist/lib/helper/shtml.js +53 -0
  39. package/dist/lib/helper/sjs.d.ts +7 -0
  40. package/dist/lib/helper/sjs.js +36 -0
  41. package/dist/lib/helper/sjson.d.ts +4 -0
  42. package/dist/lib/helper/sjson.js +32 -0
  43. package/dist/lib/helper/spath.d.ts +7 -0
  44. package/dist/lib/helper/spath.js +16 -0
  45. package/dist/lib/helper/surl.d.ts +6 -0
  46. package/dist/lib/helper/surl.js +25 -0
  47. package/dist/lib/middlewares/csp.d.ts +7 -0
  48. package/dist/lib/middlewares/csp.js +46 -0
  49. package/dist/lib/middlewares/csrf.d.ts +7 -0
  50. package/dist/lib/middlewares/csrf.js +33 -0
  51. package/dist/lib/middlewares/dta.d.ts +6 -0
  52. package/dist/lib/middlewares/dta.js +13 -0
  53. package/dist/lib/middlewares/hsts.d.ts +7 -0
  54. package/dist/lib/middlewares/hsts.js +19 -0
  55. package/dist/lib/middlewares/index.d.ts +18 -0
  56. package/dist/lib/middlewares/index.js +27 -0
  57. package/dist/lib/middlewares/methodnoallow.d.ts +6 -0
  58. package/dist/lib/middlewares/methodnoallow.js +15 -0
  59. package/dist/lib/middlewares/noopen.d.ts +7 -0
  60. package/dist/lib/middlewares/noopen.js +17 -0
  61. package/dist/lib/middlewares/nosniff.d.ts +7 -0
  62. package/dist/lib/middlewares/nosniff.js +27 -0
  63. package/dist/lib/middlewares/referrerPolicy.d.ts +7 -0
  64. package/dist/lib/middlewares/referrerPolicy.js +31 -0
  65. package/dist/lib/middlewares/xframe.d.ts +7 -0
  66. package/dist/lib/middlewares/xframe.js +18 -0
  67. package/dist/lib/middlewares/xssProtection.d.ts +7 -0
  68. package/dist/lib/middlewares/xssProtection.js +17 -0
  69. package/dist/lib/utils.d.ts +24 -0
  70. package/dist/lib/utils.js +127 -0
  71. package/dist/types.d.ts +12 -0
  72. package/dist/types.js +5 -0
  73. package/package.json +74 -70
  74. package/dist/commonjs/agent.d.ts +0 -6
  75. package/dist/commonjs/agent.js +0 -14
  76. package/dist/commonjs/app/extend/agent.d.ts +0 -5
  77. package/dist/commonjs/app/extend/agent.js +0 -11
  78. package/dist/commonjs/app/extend/application.d.ts +0 -16
  79. package/dist/commonjs/app/extend/application.js +0 -35
  80. package/dist/commonjs/app/extend/context.d.ts +0 -68
  81. package/dist/commonjs/app/extend/context.js +0 -283
  82. package/dist/commonjs/app/extend/helper.d.ts +0 -12
  83. package/dist/commonjs/app/extend/helper.js +0 -10
  84. package/dist/commonjs/app/extend/response.d.ts +0 -41
  85. package/dist/commonjs/app/extend/response.js +0 -85
  86. package/dist/commonjs/app/middleware/securities.d.ts +0 -4
  87. package/dist/commonjs/app/middleware/securities.js +0 -55
  88. package/dist/commonjs/app.d.ts +0 -6
  89. package/dist/commonjs/app.js +0 -29
  90. package/dist/commonjs/config/config.default.d.ts +0 -871
  91. package/dist/commonjs/config/config.default.js +0 -357
  92. package/dist/commonjs/config/config.local.d.ts +0 -5
  93. package/dist/commonjs/config/config.local.js +0 -10
  94. package/dist/commonjs/index.d.ts +0 -1
  95. package/dist/commonjs/index.js +0 -4
  96. package/dist/commonjs/lib/extend/safe_curl.d.ts +0 -16
  97. package/dist/commonjs/lib/extend/safe_curl.js +0 -28
  98. package/dist/commonjs/lib/helper/cliFilter.d.ts +0 -4
  99. package/dist/commonjs/lib/helper/cliFilter.js +0 -20
  100. package/dist/commonjs/lib/helper/escape.d.ts +0 -2
  101. package/dist/commonjs/lib/helper/escape.js +0 -8
  102. package/dist/commonjs/lib/helper/escapeShellArg.d.ts +0 -1
  103. package/dist/commonjs/lib/helper/escapeShellArg.js +0 -8
  104. package/dist/commonjs/lib/helper/escapeShellCmd.d.ts +0 -1
  105. package/dist/commonjs/lib/helper/escapeShellCmd.js +0 -17
  106. package/dist/commonjs/lib/helper/index.d.ts +0 -21
  107. package/dist/commonjs/lib/helper/index.js +0 -26
  108. package/dist/commonjs/lib/helper/shtml.d.ts +0 -2
  109. package/dist/commonjs/lib/helper/shtml.js +0 -76
  110. package/dist/commonjs/lib/helper/sjs.d.ts +0 -4
  111. package/dist/commonjs/lib/helper/sjs.js +0 -52
  112. package/dist/commonjs/lib/helper/sjson.d.ts +0 -1
  113. package/dist/commonjs/lib/helper/sjson.js +0 -45
  114. package/dist/commonjs/lib/helper/spath.d.ts +0 -5
  115. package/dist/commonjs/lib/helper/spath.js +0 -28
  116. package/dist/commonjs/lib/helper/surl.d.ts +0 -2
  117. package/dist/commonjs/lib/helper/surl.js +0 -33
  118. package/dist/commonjs/lib/middlewares/csp.d.ts +0 -4
  119. package/dist/commonjs/lib/middlewares/csp.js +0 -68
  120. package/dist/commonjs/lib/middlewares/csrf.d.ts +0 -4
  121. package/dist/commonjs/lib/middlewares/csrf.js +0 -42
  122. package/dist/commonjs/lib/middlewares/dta.d.ts +0 -3
  123. package/dist/commonjs/lib/middlewares/dta.js +0 -14
  124. package/dist/commonjs/lib/middlewares/hsts.d.ts +0 -4
  125. package/dist/commonjs/lib/middlewares/hsts.js +0 -23
  126. package/dist/commonjs/lib/middlewares/index.d.ts +0 -13
  127. package/dist/commonjs/lib/middlewares/index.js +0 -28
  128. package/dist/commonjs/lib/middlewares/methodnoallow.d.ts +0 -3
  129. package/dist/commonjs/lib/middlewares/methodnoallow.js +0 -22
  130. package/dist/commonjs/lib/middlewares/noopen.d.ts +0 -4
  131. package/dist/commonjs/lib/middlewares/noopen.js +0 -17
  132. package/dist/commonjs/lib/middlewares/nosniff.d.ts +0 -4
  133. package/dist/commonjs/lib/middlewares/nosniff.js +0 -30
  134. package/dist/commonjs/lib/middlewares/referrerPolicy.d.ts +0 -4
  135. package/dist/commonjs/lib/middlewares/referrerPolicy.js +0 -36
  136. package/dist/commonjs/lib/middlewares/xframe.d.ts +0 -4
  137. package/dist/commonjs/lib/middlewares/xframe.js +0 -19
  138. package/dist/commonjs/lib/middlewares/xssProtection.d.ts +0 -4
  139. package/dist/commonjs/lib/middlewares/xssProtection.js +0 -16
  140. package/dist/commonjs/lib/utils.d.ts +0 -19
  141. package/dist/commonjs/lib/utils.js +0 -206
  142. package/dist/commonjs/package.json +0 -3
  143. package/dist/commonjs/types.d.ts +0 -10
  144. package/dist/commonjs/types.js +0 -5
  145. package/dist/esm/agent.d.ts +0 -6
  146. package/dist/esm/agent.js +0 -11
  147. package/dist/esm/app/extend/agent.d.ts +0 -5
  148. package/dist/esm/app/extend/agent.js +0 -8
  149. package/dist/esm/app/extend/application.d.ts +0 -16
  150. package/dist/esm/app/extend/application.js +0 -32
  151. package/dist/esm/app/extend/context.d.ts +0 -68
  152. package/dist/esm/app/extend/context.js +0 -244
  153. package/dist/esm/app/extend/helper.d.ts +0 -12
  154. package/dist/esm/app/extend/helper.js +0 -5
  155. package/dist/esm/app/extend/response.d.ts +0 -41
  156. package/dist/esm/app/extend/response.js +0 -82
  157. package/dist/esm/app/middleware/securities.d.ts +0 -4
  158. package/dist/esm/app/middleware/securities.js +0 -50
  159. package/dist/esm/app.d.ts +0 -6
  160. package/dist/esm/app.js +0 -26
  161. package/dist/esm/config/config.default.d.ts +0 -871
  162. package/dist/esm/config/config.default.js +0 -351
  163. package/dist/esm/config/config.local.d.ts +0 -5
  164. package/dist/esm/config/config.local.js +0 -8
  165. package/dist/esm/index.d.ts +0 -1
  166. package/dist/esm/index.js +0 -2
  167. package/dist/esm/lib/extend/safe_curl.d.ts +0 -16
  168. package/dist/esm/lib/extend/safe_curl.js +0 -25
  169. package/dist/esm/lib/helper/cliFilter.d.ts +0 -4
  170. package/dist/esm/lib/helper/cliFilter.js +0 -17
  171. package/dist/esm/lib/helper/escape.d.ts +0 -2
  172. package/dist/esm/lib/helper/escape.js +0 -3
  173. package/dist/esm/lib/helper/escapeShellArg.d.ts +0 -1
  174. package/dist/esm/lib/helper/escapeShellArg.js +0 -5
  175. package/dist/esm/lib/helper/escapeShellCmd.d.ts +0 -1
  176. package/dist/esm/lib/helper/escapeShellCmd.js +0 -14
  177. package/dist/esm/lib/helper/index.d.ts +0 -21
  178. package/dist/esm/lib/helper/index.js +0 -21
  179. package/dist/esm/lib/helper/shtml.d.ts +0 -2
  180. package/dist/esm/lib/helper/shtml.js +0 -70
  181. package/dist/esm/lib/helper/sjs.d.ts +0 -4
  182. package/dist/esm/lib/helper/sjs.js +0 -49
  183. package/dist/esm/lib/helper/sjson.d.ts +0 -1
  184. package/dist/esm/lib/helper/sjson.js +0 -39
  185. package/dist/esm/lib/helper/spath.d.ts +0 -5
  186. package/dist/esm/lib/helper/spath.js +0 -25
  187. package/dist/esm/lib/helper/surl.d.ts +0 -2
  188. package/dist/esm/lib/helper/surl.js +0 -30
  189. package/dist/esm/lib/middlewares/csp.d.ts +0 -4
  190. package/dist/esm/lib/middlewares/csp.js +0 -63
  191. package/dist/esm/lib/middlewares/csrf.d.ts +0 -4
  192. package/dist/esm/lib/middlewares/csrf.js +0 -37
  193. package/dist/esm/lib/middlewares/dta.d.ts +0 -3
  194. package/dist/esm/lib/middlewares/dta.js +0 -12
  195. package/dist/esm/lib/middlewares/hsts.d.ts +0 -4
  196. package/dist/esm/lib/middlewares/hsts.js +0 -21
  197. package/dist/esm/lib/middlewares/index.d.ts +0 -13
  198. package/dist/esm/lib/middlewares/index.js +0 -23
  199. package/dist/esm/lib/middlewares/methodnoallow.d.ts +0 -3
  200. package/dist/esm/lib/middlewares/methodnoallow.js +0 -20
  201. package/dist/esm/lib/middlewares/noopen.d.ts +0 -4
  202. package/dist/esm/lib/middlewares/noopen.js +0 -15
  203. package/dist/esm/lib/middlewares/nosniff.d.ts +0 -4
  204. package/dist/esm/lib/middlewares/nosniff.js +0 -28
  205. package/dist/esm/lib/middlewares/referrerPolicy.d.ts +0 -4
  206. package/dist/esm/lib/middlewares/referrerPolicy.js +0 -34
  207. package/dist/esm/lib/middlewares/xframe.d.ts +0 -4
  208. package/dist/esm/lib/middlewares/xframe.js +0 -17
  209. package/dist/esm/lib/middlewares/xssProtection.d.ts +0 -4
  210. package/dist/esm/lib/middlewares/xssProtection.js +0 -14
  211. package/dist/esm/lib/utils.d.ts +0 -19
  212. package/dist/esm/lib/utils.js +0 -194
  213. package/dist/esm/package.json +0 -3
  214. package/dist/esm/types.d.ts +0 -10
  215. package/dist/esm/types.js +0 -3
  216. package/dist/package.json +0 -4
  217. package/src/agent.ts +0 -14
  218. package/src/app/extend/agent.ts +0 -14
  219. package/src/app/extend/application.ts +0 -51
  220. package/src/app/extend/context.ts +0 -285
  221. package/src/app/extend/helper.ts +0 -5
  222. package/src/app/extend/response.ts +0 -95
  223. package/src/app/middleware/securities.ts +0 -63
  224. package/src/app.ts +0 -31
  225. package/src/config/config.default.ts +0 -379
  226. package/src/config/config.local.ts +0 -9
  227. package/src/index.ts +0 -1
  228. package/src/lib/extend/safe_curl.ts +0 -35
  229. package/src/lib/helper/cliFilter.ts +0 -20
  230. package/src/lib/helper/escape.ts +0 -3
  231. package/src/lib/helper/escapeShellArg.ts +0 -4
  232. package/src/lib/helper/escapeShellCmd.ts +0 -16
  233. package/src/lib/helper/index.ts +0 -21
  234. package/src/lib/helper/shtml.ts +0 -77
  235. package/src/lib/helper/sjs.ts +0 -57
  236. package/src/lib/helper/sjson.ts +0 -35
  237. package/src/lib/helper/spath.ts +0 -27
  238. package/src/lib/helper/surl.ts +0 -35
  239. package/src/lib/middlewares/csp.ts +0 -70
  240. package/src/lib/middlewares/csrf.ts +0 -44
  241. package/src/lib/middlewares/dta.ts +0 -13
  242. package/src/lib/middlewares/hsts.ts +0 -24
  243. package/src/lib/middlewares/index.ts +0 -23
  244. package/src/lib/middlewares/methodnoallow.ts +0 -23
  245. package/src/lib/middlewares/noopen.ts +0 -18
  246. package/src/lib/middlewares/nosniff.ts +0 -32
  247. package/src/lib/middlewares/referrerPolicy.ts +0 -39
  248. package/src/lib/middlewares/xframe.ts +0 -20
  249. package/src/lib/middlewares/xssProtection.ts +0 -17
  250. package/src/lib/utils.ts +0 -208
  251. package/src/types.ts +0 -16
  252. package/src/typings/index.d.ts +0 -4
@@ -1,95 +0,0 @@
1
- import { Response as KoaResponse } from '@eggjs/core';
2
- import SecurityContext from './context.js';
3
-
4
- const unsafeRedirect = KoaResponse.prototype.redirect;
5
-
6
- export default class SecurityResponse extends KoaResponse {
7
- declare ctx: SecurityContext;
8
-
9
- /**
10
- * This is an unsafe redirection, and we WON'T check if the
11
- * destination url is safe or not.
12
- * Please DO NOT use this method unless in some very special cases,
13
- * otherwise there may be security vulnerabilities.
14
- *
15
- * @function Response#unsafeRedirect
16
- * @param {String} url URL to forward
17
- * @example
18
- * ```js
19
- * ctx.response.unsafeRedirect('http://www.domain.com');
20
- * ctx.unsafeRedirect('http://www.domain.com');
21
- * ```
22
- */
23
- unsafeRedirect(url: string, alt?: string) {
24
- unsafeRedirect.call(this, url, alt);
25
- }
26
-
27
- // app.response.unsafeRedirect = app.response.redirect;
28
- // delegate(app.context, 'response').method('unsafeRedirect');
29
- /**
30
- * A safe redirection, and we'll check if the URL is in
31
- * a safe domain or not.
32
- * We've overridden the default Koa's implementation by adding a
33
- * white list as the filter for that.
34
- *
35
- * @function Response#redirect
36
- * @param {String} url URL to forward
37
- * @example
38
- * ```js
39
- * ctx.response.redirect('/login');
40
- * ctx.redirect('/login');
41
- * ```
42
- */
43
- redirect(url: string, alt?: string) {
44
- url = (url || '/').trim();
45
-
46
- // Process with `//`
47
- if (url[0] === '/' && url[1] === '/') {
48
- url = '/';
49
- }
50
-
51
- // if begin with '/', it means an internal jump
52
- if (url[0] === '/' && url[1] !== '\\') {
53
- this.unsafeRedirect(url, alt);
54
- return;
55
- }
56
-
57
- let urlObject: URL;
58
- try {
59
- urlObject = new URL(url);
60
- } catch {
61
- url = '/';
62
- this.unsafeRedirect(url);
63
- return;
64
- }
65
-
66
- const domainWhiteList = this.app.config.security.domainWhiteList;
67
- if (urlObject.protocol !== 'http:' && urlObject.protocol !== 'https:') {
68
- url = '/';
69
- } else if (!urlObject.hostname) {
70
- url = '/';
71
- } else {
72
- if (domainWhiteList && domainWhiteList.length !== 0) {
73
- if (!this.ctx.isSafeDomain(urlObject.hostname)) {
74
- const message = `a security problem has been detected for url "${url}", redirection is prohibited.`;
75
- if (process.env.NODE_ENV === 'production') {
76
- this.app.coreLogger.warn('[@eggjs/security/response/redirect] %s', message);
77
- url = '/';
78
- } else {
79
- // Exception will be thrown out in a non-PROD env.
80
- return this.ctx.throw(500, message);
81
- }
82
- }
83
- }
84
- }
85
- this.unsafeRedirect(url);
86
- }
87
- }
88
-
89
- declare module '@eggjs/core' {
90
- // add Response overrides types
91
- interface Response {
92
- unsafeRedirect(url: string, alt?: string): void;
93
- redirect(url: string, alt?: string): void;
94
- }
95
- }
@@ -1,63 +0,0 @@
1
- import assert from 'node:assert';
2
- import compose from 'koa-compose';
3
- import { pathMatching } from 'egg-path-matching';
4
- import { EggCore, MiddlewareFunc } from '@eggjs/core';
5
- import securityMiddlewares from '../../lib/middlewares/index.js';
6
- import type { SecurityMiddlewareName } from '../../config/config.default.js';
7
-
8
- export default (_: unknown, app: EggCore) => {
9
- const options = app.config.security;
10
- const middlewares: MiddlewareFunc[] = [];
11
- const defaultMiddlewares = typeof options.defaultMiddleware === 'string'
12
- ? options.defaultMiddleware.split(',').map(m => m.trim()).filter(m => !!m) as SecurityMiddlewareName[]
13
- : options.defaultMiddleware;
14
-
15
- if (options.match || options.ignore) {
16
- app.coreLogger.warn('[@eggjs/security/middleware/securities] Please set `match` or `ignore` on sub config');
17
- }
18
-
19
- // format csrf.cookieDomain
20
- const originalCookieDomain = options.csrf.cookieDomain;
21
- if (originalCookieDomain && typeof originalCookieDomain !== 'function') {
22
- options.csrf.cookieDomain = () => originalCookieDomain;
23
- }
24
-
25
- defaultMiddlewares.forEach(middlewareName => {
26
- const opt = Reflect.get(options, middlewareName) as any;
27
- if (opt === false) {
28
- app.coreLogger.warn('[egg-security] Please use `config.security.%s = { enable: false }` instead of `config.security.%s = false`', middlewareName, middlewareName);
29
- }
30
-
31
- assert(opt === false || typeof opt === 'object',
32
- `config.security.${middlewareName} must be an object, or false(if you turn it off)`);
33
-
34
- if (opt === false || opt && opt.enable === false) {
35
- return;
36
- }
37
-
38
- if (middlewareName === 'csrf' && opt.useSession && !app.plugins.session) {
39
- throw new Error('csrf.useSession enabled, but session plugin is disabled');
40
- }
41
-
42
- // use opt.match first (compatibility)
43
- if (opt.match && opt.ignore) {
44
- app.coreLogger.warn('[@eggjs/security/middleware/securities] `options.match` and `options.ignore` are both set, using `options.match`');
45
- opt.ignore = undefined;
46
- }
47
- if (!opt.ignore && opt.blackUrls) {
48
- app.deprecate('[@eggjs/security/middleware/securities] Please use `config.security.xframe.ignore` instead, `config.security.xframe.blackUrls` will be removed very soon');
49
- opt.ignore = opt.blackUrls;
50
- }
51
- // set matching function to security middleware options
52
- opt.matching = pathMatching(opt);
53
-
54
- const createMiddleware = securityMiddlewares[middlewareName];
55
- const fn = createMiddleware(opt);
56
- middlewares.push(fn);
57
- app.coreLogger.info('[@eggjs/security/middleware/securities] use %s middleware', middlewareName);
58
- });
59
-
60
- app.coreLogger.info('[@eggjs/security/middleware/securities] compose %d middlewares into one security middleware',
61
- middlewares.length);
62
- return compose(middlewares);
63
- };
package/src/app.ts DELETED
@@ -1,31 +0,0 @@
1
- import type { ILifecycleBoot, EggCore } from '@eggjs/core';
2
- import { preprocessConfig } from './lib/utils.js';
3
- import { SecurityConfig } from './config/config.default.js';
4
-
5
- export default class AppBoot implements ILifecycleBoot {
6
- private readonly app;
7
-
8
- constructor(app: EggCore) {
9
- this.app = app;
10
- }
11
-
12
- configWillLoad() {
13
- const app = this.app;
14
- app.config.coreMiddleware.push('securities');
15
- // parse config and check if config is legal
16
- const parsed = SecurityConfig.parse(app.config.security);
17
- if (typeof app.config.security.csrf === 'boolean') {
18
- // support old config: `config.security.csrf = false`
19
- app.config.security.csrf = parsed.csrf;
20
- }
21
-
22
- if (app.config.security.csrf.enable) {
23
- const { ignoreJSON } = app.config.security.csrf;
24
- if (ignoreJSON) {
25
- app.deprecate('[@eggjs/security/app] `config.security.csrf.ignoreJSON` is not safe now, please disable it.');
26
- }
27
- }
28
-
29
- preprocessConfig(app.config.security);
30
- }
31
- }
@@ -1,379 +0,0 @@
1
- import z from 'zod';
2
- import { Context } from '@eggjs/core';
3
-
4
- const CSRFSupportRequestItem = z.object({
5
- path: z.instanceof(RegExp),
6
- methods: z.array(z.string()),
7
- });
8
- export type CSRFSupportRequestItem = z.infer<typeof CSRFSupportRequestItem>;
9
-
10
- export const LookupAddress = z.object({
11
- address: z.string(),
12
- family: z.number(),
13
- });
14
- export type LookupAddress = z.infer<typeof LookupAddress>;
15
-
16
- const LookupAddressAndStringArray = z.union([ z.string(), LookupAddress ]).array();
17
- const SSRFCheckAddressFunction = z.function()
18
- .args(z.union([ z.string(), LookupAddress, LookupAddressAndStringArray ]), z.union([ z.number(), z.string() ]), z.string())
19
- .returns(z.boolean());
20
- /**
21
- * SSRF check address function
22
- * `(address, family, hostname) => boolean`
23
- */
24
- export type SSRFCheckAddressFunction = z.infer<typeof SSRFCheckAddressFunction>;
25
-
26
- export const SecurityMiddlewareName = z.enum([
27
- 'csrf',
28
- 'hsts',
29
- 'methodnoallow',
30
- 'noopen',
31
- 'nosniff',
32
- 'csp',
33
- 'xssProtection',
34
- 'xframe',
35
- 'dta',
36
- ]);
37
- export type SecurityMiddlewareName = z.infer<typeof SecurityMiddlewareName>;
38
-
39
- /**
40
- * (ctx) => boolean
41
- */
42
- const IgnoreOrMatchHandler = z.function().args(z.instanceof(Context)).returns(z.boolean());
43
- export type IgnoreOrMatchHandler = z.infer<typeof IgnoreOrMatchHandler>;
44
-
45
- const IgnoreOrMatch = z.union([
46
- z.string(), z.instanceof(RegExp), IgnoreOrMatchHandler,
47
- ]);
48
- export type IgnoreOrMatch = z.infer<typeof IgnoreOrMatch>;
49
-
50
- const IgnoreOrMatchOption = z.union([ IgnoreOrMatch, IgnoreOrMatch.array() ]).optional();
51
- export type IgnoreOrMatchOption = z.infer<typeof IgnoreOrMatchOption>;
52
-
53
- /**
54
- * security options
55
- * @member Config#security
56
- */
57
- export const SecurityConfig = z.object({
58
- /**
59
- * domain white list
60
- *
61
- * Default to `[]`
62
- */
63
- domainWhiteList: z.array(z.string()).default([]),
64
- /**
65
- * protocol white list
66
- *
67
- * Default to `[]`
68
- */
69
- protocolWhiteList: z.array(z.string()).default([]),
70
- /**
71
- * default open security middleware
72
- *
73
- * Default to `'csrf,hsts,methodnoallow,noopen,nosniff,csp,xssProtection,xframe,dta'`
74
- */
75
- defaultMiddleware: z.union([ z.string(), z.array(SecurityMiddlewareName) ])
76
- .default(SecurityMiddlewareName.options),
77
- /**
78
- * whether defend csrf attack
79
- */
80
- csrf: z.preprocess(val => {
81
- // transform old config, `csrf: false` to `csrf: { enable: false }`
82
- if (typeof val === 'boolean') {
83
- return { enable: val };
84
- }
85
- return val;
86
- }, z.object({
87
- match: IgnoreOrMatchOption,
88
- ignore: IgnoreOrMatchOption,
89
- /**
90
- * Default to `true`
91
- */
92
- enable: z.boolean().default(true),
93
- /**
94
- * csrf token detect source type
95
- *
96
- * Default to `'ctoken'`
97
- */
98
- type: z.enum([ 'ctoken', 'referer', 'all', 'any' ]).default('ctoken'),
99
- /**
100
- * ignore json request
101
- *
102
- * Default to `false`
103
- *
104
- * @deprecated is not safe now, don't use it
105
- */
106
- ignoreJSON: z.boolean().default(false),
107
- /**
108
- * csrf token cookie name
109
- *
110
- * Default to `'csrfToken'`
111
- */
112
- cookieName: z.union([ z.string(), z.array(z.string()) ]).default('csrfToken'),
113
- /**
114
- * csrf token session name
115
- *
116
- * Default to `'csrfToken'`
117
- */
118
- sessionName: z.string().default('csrfToken'),
119
- /**
120
- * csrf token request header name
121
- *
122
- * Default to `'x-csrf-token'`
123
- */
124
- headerName: z.string().default('x-csrf-token'),
125
- /**
126
- * csrf token request body field name
127
- *
128
- * Default to `'_csrf'`
129
- */
130
- bodyName: z.union([ z.string(), z.array(z.string()) ]).default('_csrf'),
131
- /**
132
- * csrf token request query field name
133
- *
134
- * Default to `'_csrf'`
135
- */
136
- queryName: z.union([ z.string(), z.array(z.string()) ]).default('_csrf'),
137
- /**
138
- * rotate csrf token when it is invalid
139
- *
140
- * Default to `false`
141
- */
142
- rotateWhenInvalid: z.boolean().default(false),
143
- /**
144
- * These config works when using `'ctoken'` type
145
- *
146
- * Default to `false`
147
- */
148
- useSession: z.boolean().default(false),
149
- /**
150
- * csrf token cookie domain setting,
151
- * can be `(ctx) => string` or `string`
152
- *
153
- * Default to `undefined`, auto set the cookie domain in the safe way
154
- */
155
- cookieDomain: z.union([
156
- z.string(),
157
- z.function()
158
- .args(z.instanceof(Context))
159
- .returns(z.string()),
160
- ]).optional(),
161
- /**
162
- * csrf token check requests config
163
- */
164
- supportedRequests: z.array(CSRFSupportRequestItem)
165
- .default([
166
- { path: /^\//, methods: [ 'POST', 'PATCH', 'DELETE', 'PUT', 'CONNECT' ] },
167
- ]),
168
- /**
169
- * referer or origin header white list.
170
- * It only works when using `'referer'` type
171
- *
172
- * Default to `[]`
173
- */
174
- refererWhiteList: z.array(z.string()).default([]),
175
- /**
176
- * csrf token cookie options
177
- *
178
- * Default to `{
179
- * signed: false,
180
- * httpOnly: false,
181
- * overwrite: true,
182
- * }`
183
- */
184
- cookieOptions: z.object({
185
- signed: z.boolean(),
186
- httpOnly: z.boolean(),
187
- overwrite: z.boolean(),
188
- }).default({
189
- signed: false,
190
- httpOnly: false,
191
- overwrite: true,
192
- }),
193
- }).default({})),
194
- /**
195
- * whether enable X-Frame-Options response header
196
- */
197
- xframe: z.object({
198
- match: IgnoreOrMatchOption,
199
- ignore: IgnoreOrMatchOption,
200
- /**
201
- * Default to `true`
202
- */
203
- enable: z.boolean().default(true),
204
- /**
205
- * X-Frame-Options value, can be `'DENY'`, `'SAMEORIGIN'`, `'ALLOW-FROM https://example.com'`
206
- *
207
- * Default to `'SAMEORIGIN'`
208
- */
209
- value: z.string().default('SAMEORIGIN'),
210
- }).default({}),
211
- /**
212
- * whether enable Strict-Transport-Security response header
213
- */
214
- hsts: z.object({
215
- match: IgnoreOrMatchOption,
216
- ignore: IgnoreOrMatchOption,
217
- /**
218
- * Default to `false`
219
- */
220
- enable: z.boolean().default(false),
221
- /**
222
- * Max age of Strict-Transport-Security in seconds
223
- *
224
- * Default to `365 * 24 * 3600`
225
- */
226
- maxAge: z.number().default(365 * 24 * 3600),
227
- /**
228
- * Whether include sub domains
229
- *
230
- * Default to `false`
231
- */
232
- includeSubdomains: z.boolean().default(false),
233
- }).default({}),
234
- /**
235
- * whether enable Http Method filter
236
- */
237
- methodnoallow: z.object({
238
- match: IgnoreOrMatchOption,
239
- ignore: IgnoreOrMatchOption,
240
- /**
241
- * Default to `true`
242
- */
243
- enable: z.boolean().default(true),
244
- }).default({}),
245
- /**
246
- * whether enable IE automatically download open
247
- */
248
- noopen: z.object({
249
- match: IgnoreOrMatchOption,
250
- ignore: IgnoreOrMatchOption,
251
- /**
252
- * Default to `true`
253
- */
254
- enable: z.boolean().default(true),
255
- }).default({}),
256
- /**
257
- * whether enable IE8 automatically detect mime
258
- */
259
- nosniff: z.object({
260
- match: IgnoreOrMatchOption,
261
- ignore: IgnoreOrMatchOption,
262
- /**
263
- * Default to `true`
264
- */
265
- enable: z.boolean().default(true),
266
- }).default({}),
267
- /**
268
- * whether enable IE8 XSS Filter
269
- */
270
- xssProtection: z.object({
271
- match: IgnoreOrMatchOption,
272
- ignore: IgnoreOrMatchOption,
273
- /**
274
- * Default to `true`
275
- */
276
- enable: z.boolean().default(true),
277
- /**
278
- * X-XSS-Protection response header value
279
- *
280
- * Default to `'1; mode=block'`
281
- */
282
- value: z.coerce.string().default('1; mode=block'),
283
- }).default({}),
284
- /**
285
- * content security policy config
286
- */
287
- csp: z.object({
288
- match: IgnoreOrMatchOption,
289
- ignore: IgnoreOrMatchOption,
290
- /**
291
- * Default to `false`
292
- */
293
- enable: z.boolean().default(false),
294
- // https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP#csp_overview
295
- policy: z.record(z.union([ z.string(), z.array(z.string()), z.boolean() ])).default({}),
296
- /**
297
- * whether enable report only mode
298
- * Default to `undefined`
299
- */
300
- reportOnly: z.boolean().optional(),
301
- /**
302
- * whether support IE
303
- * Default to `undefined`
304
- */
305
- supportIE: z.boolean().optional(),
306
- }).default({}),
307
- /**
308
- * whether enable referrer policy
309
- * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
310
- */
311
- referrerPolicy: z.object({
312
- match: IgnoreOrMatchOption,
313
- ignore: IgnoreOrMatchOption,
314
- /**
315
- * Default to `false`
316
- */
317
- enable: z.boolean().default(false),
318
- /**
319
- * referrer policy value
320
- *
321
- * Default to `'no-referrer-when-downgrade'`
322
- */
323
- value: z.string().default('no-referrer-when-downgrade'),
324
- }).default({}),
325
- /**
326
- * whether enable auto avoid directory traversal attack
327
- */
328
- dta: z.object({
329
- match: IgnoreOrMatchOption,
330
- ignore: IgnoreOrMatchOption,
331
- /**
332
- * Default to `true`
333
- */
334
- enable: z.boolean().default(true),
335
- }).default({}),
336
- ssrf: z.object({
337
- ipBlackList: z.array(z.string()).optional(),
338
- ipExceptionList: z.array(z.string()).optional(),
339
- hostnameExceptionList: z.array(z.string()).optional(),
340
- checkAddress: SSRFCheckAddressFunction.optional(),
341
- }).default({}),
342
- match: z.union([ IgnoreOrMatch, IgnoreOrMatch.array() ]).optional(),
343
- ignore: z.union([ IgnoreOrMatch, IgnoreOrMatch.array() ]).optional(),
344
- __protocolWhiteListSet: z.set(z.string()).optional().readonly(),
345
- });
346
- export type SecurityConfig = z.infer<typeof SecurityConfig>;
347
-
348
- const SecurityHelperOnTagAttrHandler = z.function()
349
- .args(z.string(), z.string(), z.string(), z.boolean())
350
- .returns(z.union([ z.string(), z.void() ]));
351
-
352
- /**
353
- * (tag: string, name: string, value: string, isWhiteAttr: boolean) => string | void
354
- */
355
- export type SecurityHelperOnTagAttrHandler = z.infer<typeof SecurityHelperOnTagAttrHandler>;
356
-
357
- export const SecurityHelperConfig = z.object({
358
- shtml: z.object({
359
- /**
360
- * tag attribute white list
361
- */
362
- whiteList: z.record(z.array(z.string())).optional(),
363
- /**
364
- * domain white list
365
- * @deprecated use `config.security.domainWhiteList` instead
366
- */
367
- domainWhiteList: z.array(z.string()).optional(),
368
- /**
369
- * tag attribute handler
370
- */
371
- onTagAttr: SecurityHelperOnTagAttrHandler.optional(),
372
- }).default({}),
373
- });
374
- export type SecurityHelperConfig = z.infer<typeof SecurityHelperConfig>;
375
-
376
- export default {
377
- security: SecurityConfig.parse({}),
378
- helper: SecurityHelperConfig.parse({}),
379
- };
@@ -1,9 +0,0 @@
1
- import { SecurityConfig } from '../types.js';
2
-
3
- export default {
4
- security: {
5
- hsts: {
6
- enable: false,
7
- },
8
- } as SecurityConfig,
9
- };
package/src/index.ts DELETED
@@ -1 +0,0 @@
1
- import './types.js';
@@ -1,35 +0,0 @@
1
- import { EggCore } from '@eggjs/core';
2
- import type { SSRFCheckAddressFunction } from '../../types.js';
3
-
4
- const SSRF_HTTPCLIENT = Symbol('SSRF_HTTPCLIENT');
5
-
6
- type HttpClient = EggCore['HttpClient'];
7
- type HttpClientParameters = Parameters<HttpClient['prototype']['request']>;
8
- export type HttpClientRequestURL = HttpClientParameters[0];
9
- export type HttpClientOptions = HttpClientParameters[1] & { checkAddress?: SSRFCheckAddressFunction };
10
- export type HttpClientResponse<T = any> = Awaited<ReturnType<HttpClient['prototype']['request']>> & { data: T };
11
-
12
- /**
13
- * safe curl with ssrf protection
14
- */
15
- export async function safeCurlForApplication<T = any>(app: EggCore, url: HttpClientRequestURL, options: HttpClientOptions = {}) {
16
- const ssrfConfig = app.config.security.ssrf;
17
- if (ssrfConfig?.checkAddress) {
18
- options.checkAddress = ssrfConfig.checkAddress;
19
- } else {
20
- app.logger.warn('[@eggjs/security] please configure `config.security.ssrf` first');
21
- }
22
-
23
- if (ssrfConfig?.checkAddress) {
24
- let httpClient = app[SSRF_HTTPCLIENT] as ReturnType<EggCore['createHttpClient']>;
25
- // use the new httpClient init with checkAddress
26
- if (!httpClient) {
27
- httpClient = app[SSRF_HTTPCLIENT] = app.createHttpClient({
28
- checkAddress: ssrfConfig.checkAddress,
29
- });
30
- }
31
- return await httpClient.request<T>(url, options);
32
- }
33
-
34
- return await app.curl<T>(url, options);
35
- }
@@ -1,20 +0,0 @@
1
- /**
2
- * remote command execution
3
- */
4
-
5
- const BASIC_ALPHABETS = new Set('abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ.-_'.split(''));
6
-
7
- export default function cliFilter(text: string) {
8
- const str = '' + text;
9
- let res = '';
10
- let ascii;
11
-
12
- for (let index = 0; index < str.length; index++) {
13
- ascii = str[index];
14
- if (BASIC_ALPHABETS.has(ascii)) {
15
- res += ascii;
16
- }
17
- }
18
-
19
- return res;
20
- }
@@ -1,3 +0,0 @@
1
- import escapeHTML from 'escape-html';
2
-
3
- export default escapeHTML;
@@ -1,4 +0,0 @@
1
- export default function escapeShellArg(text: string) {
2
- const str = '' + text;
3
- return '\'' + str.replace(/\\/g, '\\\\').replace(/\'/g, '\\\'') + '\'';
4
- }
@@ -1,16 +0,0 @@
1
- const BASIC_ALPHABETS = new Set('#&;`|*?~<>^()[]{}$;\'",\x0A\xFF'.split(''));
2
-
3
- export default function escapeShellCmd(text: string) {
4
- const str = '' + text;
5
- let res = '';
6
- let ascii;
7
-
8
- for (let index = 0; index < str.length; index++) {
9
- ascii = str[index];
10
- if (!BASIC_ALPHABETS.has(ascii)) {
11
- res += ascii;
12
- }
13
- }
14
-
15
- return res;
16
- }
@@ -1,21 +0,0 @@
1
- import cliFilter from './cliFilter.js';
2
- import escape from './escape.js';
3
- import escapeShellArg from './escapeShellArg.js';
4
- import escapeShellCmd from './escapeShellCmd.js';
5
- import shtml from './shtml.js';
6
- import sjs from './sjs.js';
7
- import sjson from './sjson.js';
8
- import spath from './spath.js';
9
- import surl from './surl.js';
10
-
11
- export default {
12
- cliFilter,
13
- escape,
14
- escapeShellArg,
15
- escapeShellCmd,
16
- shtml,
17
- sjs,
18
- sjson,
19
- spath,
20
- surl,
21
- };