@eggjs/security 5.0.0-beta.34 → 5.0.0-beta.36

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 (71) hide show
  1. package/dist/agent.d.ts +9 -5
  2. package/dist/agent.js +14 -10
  3. package/dist/app/extend/agent.d.ts +8 -4
  4. package/dist/app/extend/agent.js +12 -8
  5. package/dist/app/extend/application.d.ts +11 -7
  6. package/dist/app/extend/application.js +32 -32
  7. package/dist/app/extend/context.d.ts +55 -51
  8. package/dist/app/extend/context.js +185 -240
  9. package/dist/app/extend/helper.d.ts +5 -2
  10. package/dist/app/extend/helper.js +8 -6
  11. package/dist/app/extend/response.d.ts +38 -34
  12. package/dist/app/extend/response.js +69 -82
  13. package/dist/app/middleware/securities.d.ts +5 -2
  14. package/dist/app/middleware/securities.js +38 -52
  15. package/dist/app.d.ts +9 -5
  16. package/dist/app.js +22 -24
  17. package/dist/config/config.default.d.ts +34 -45
  18. package/dist/config/config.default.js +158 -362
  19. package/dist/config/config.local.d.ts +6 -3
  20. package/dist/config/config.local.js +6 -8
  21. package/dist/index.d.ts +20 -16
  22. package/dist/index.js +24 -21
  23. package/dist/lib/extend/safe_curl.d.ts +16 -13
  24. package/dist/lib/extend/safe_curl.js +17 -23
  25. package/dist/lib/helper/cliFilter.d.ts +4 -4
  26. package/dist/lib/helper/cliFilter.js +16 -15
  27. package/dist/lib/helper/escape.d.ts +2 -2
  28. package/dist/lib/helper/escape.js +7 -3
  29. package/dist/lib/helper/escapeShellArg.d.ts +4 -1
  30. package/dist/lib/helper/escapeShellArg.js +6 -4
  31. package/dist/lib/helper/escapeShellCmd.d.ts +4 -1
  32. package/dist/lib/helper/escapeShellCmd.js +14 -13
  33. package/dist/lib/helper/index.d.ts +22 -19
  34. package/dist/lib/helper/index.js +19 -15
  35. package/dist/lib/helper/shtml.d.ts +6 -2
  36. package/dist/lib/helper/shtml.js +52 -68
  37. package/dist/lib/helper/sjs.d.ts +4 -4
  38. package/dist/lib/helper/sjs.js +31 -44
  39. package/dist/lib/helper/sjson.d.ts +4 -1
  40. package/dist/lib/helper/sjson.js +28 -35
  41. package/dist/lib/helper/spath.d.ts +7 -5
  42. package/dist/lib/helper/spath.js +15 -24
  43. package/dist/lib/helper/surl.d.ts +6 -2
  44. package/dist/lib/helper/surl.js +22 -27
  45. package/dist/lib/middlewares/csp.d.ts +6 -3
  46. package/dist/lib/middlewares/csp.js +43 -54
  47. package/dist/lib/middlewares/csrf.d.ts +6 -3
  48. package/dist/lib/middlewares/csrf.js +31 -35
  49. package/dist/lib/middlewares/dta.d.ts +5 -2
  50. package/dist/lib/middlewares/dta.js +11 -10
  51. package/dist/lib/middlewares/hsts.d.ts +6 -3
  52. package/dist/lib/middlewares/hsts.js +17 -19
  53. package/dist/lib/middlewares/index.d.ts +24 -21
  54. package/dist/lib/middlewares/index.js +26 -22
  55. package/dist/lib/middlewares/methodnoallow.d.ts +5 -2
  56. package/dist/lib/middlewares/methodnoallow.js +13 -18
  57. package/dist/lib/middlewares/noopen.d.ts +6 -3
  58. package/dist/lib/middlewares/noopen.js +14 -13
  59. package/dist/lib/middlewares/nosniff.d.ts +6 -3
  60. package/dist/lib/middlewares/nosniff.js +22 -24
  61. package/dist/lib/middlewares/referrerPolicy.d.ts +6 -3
  62. package/dist/lib/middlewares/referrerPolicy.js +27 -30
  63. package/dist/lib/middlewares/xframe.d.ts +6 -3
  64. package/dist/lib/middlewares/xframe.js +16 -15
  65. package/dist/lib/middlewares/xssProtection.d.ts +6 -3
  66. package/dist/lib/middlewares/xssProtection.js +15 -12
  67. package/dist/lib/utils.d.ts +22 -17
  68. package/dist/lib/utils.js +112 -177
  69. package/dist/types.d.ts +38 -36
  70. package/dist/types.js +1 -2
  71. package/package.json +31 -37
@@ -1,243 +1,188 @@
1
- import { debuglog } from 'node:util';
2
- import { nanoid } from 'nanoid/non-secure';
3
- import Tokens from 'csrf';
4
- import { Context } from 'egg';
5
- import * as utils from "../../lib/utils.js";
6
- const debug = debuglog('egg/security/app/extend/context');
1
+ import { checkIfIgnore, getFromUrl, isSafeDomain } from "../../lib/utils.js";
2
+ import { Context } from "egg";
3
+ import { debuglog } from "node:util";
4
+ import Tokens from "csrf";
5
+ import { nanoid } from "nanoid/non-secure";
6
+
7
+ //#region src/app/extend/context.ts
8
+ const debug = debuglog("egg/security/app/extend/context");
7
9
  const tokens = new Tokens();
8
- const _CSRF_SECRET = Symbol('egg-security#_CSRF_SECRET');
9
- const NEW_CSRF_SECRET = Symbol('egg-security#NEW_CSRF_SECRET');
10
- const NONCE_CACHE = Symbol('egg-security#NONCE_CACHE');
11
- const SECURITY_OPTIONS = Symbol('egg-security#SECURITY_OPTIONS');
10
+ const _CSRF_SECRET = Symbol("egg-security#_CSRF_SECRET");
11
+ const NEW_CSRF_SECRET = Symbol("egg-security#NEW_CSRF_SECRET");
12
+ const NONCE_CACHE = Symbol("egg-security#NONCE_CACHE");
13
+ const SECURITY_OPTIONS = Symbol("egg-security#SECURITY_OPTIONS");
12
14
  function findToken(obj, keys) {
13
- if (!obj)
14
- return;
15
- if (!keys || !keys.length)
16
- return;
17
- if (typeof keys === 'string')
18
- return obj[keys];
19
- for (const key of keys) {
20
- if (obj[key])
21
- return obj[key];
22
- }
15
+ if (!obj) return;
16
+ if (!keys || !keys.length) return;
17
+ if (typeof keys === "string") return obj[keys];
18
+ for (const key of keys) if (obj[key]) return obj[key];
23
19
  }
24
- export default class SecurityContext extends Context {
25
- get securityOptions() {
26
- if (!this[SECURITY_OPTIONS]) {
27
- this[SECURITY_OPTIONS] = {};
28
- }
29
- return this[SECURITY_OPTIONS];
30
- }
31
- /**
32
- * Check whether the specific `domain` is in / matches the whiteList or not.
33
- * @param {string} domain The assigned domain.
34
- * @param {Array<string>} [customWhiteList] The custom white list for domain.
35
- * @return {boolean} If the domain is in / matches the whiteList, return true;
36
- * otherwise false.
37
- */
38
- isSafeDomain(domain, customWhiteList) {
39
- const domainWhiteList = customWhiteList && customWhiteList.length > 0 ? customWhiteList : this.app.config.security.domainWhiteList;
40
- return utils.isSafeDomain(domain, domainWhiteList);
41
- }
42
- // Add nonce, random characters will be OK.
43
- // https://w3c.github.io/webappsec/specs/content-security-policy/#nonce_source
44
- get nonce() {
45
- if (!this[NONCE_CACHE]) {
46
- this[NONCE_CACHE] = nanoid(16);
47
- }
48
- return this[NONCE_CACHE];
49
- }
50
- /**
51
- * get csrf token, general use in template
52
- * @return {String} csrf token
53
- * @public
54
- */
55
- get csrf() {
56
- // csrfSecret can be rotate, use NEW_CSRF_SECRET first
57
- const secret = this[NEW_CSRF_SECRET] || this.getCsrfSecret();
58
- debug('get csrf token, NEW_CSRF_SECRET: %s, _CSRF_SECRET: %s', this[NEW_CSRF_SECRET], this.getCsrfSecret());
59
- // In order to protect against BREACH attacks,
60
- // the token is not simply the secret;
61
- // a random salt is prepended to the secret and used to scramble it.
62
- // http://breachattack.com/
63
- return secret ? tokens.create(secret) : '';
64
- }
65
- /**
66
- * get csrf secret from session or cookie
67
- * @return {String} csrf secret
68
- * @private
69
- */
70
- getCsrfSecret() {
71
- if (this[_CSRF_SECRET]) {
72
- return this[_CSRF_SECRET];
73
- }
74
- let { useSession, sessionName, cookieName: cookieNames, cookieOptions } = this.app.config.security.csrf;
75
- // get secret from session or cookie
76
- if (useSession) {
77
- this[_CSRF_SECRET] = this.session[sessionName] || '';
78
- }
79
- else {
80
- // cookieName support array. so we can change csrf cookie name smoothly
81
- if (!Array.isArray(cookieNames)) {
82
- cookieNames = [cookieNames];
83
- }
84
- for (const cookieName of cookieNames) {
85
- this[_CSRF_SECRET] = this.cookies.get(cookieName, { signed: cookieOptions.signed }) || '';
86
- if (this[_CSRF_SECRET]) {
87
- break;
88
- }
89
- }
90
- }
91
- return this[_CSRF_SECRET];
92
- }
93
- /**
94
- * ensure csrf secret exists in session or cookie.
95
- * @param {Boolean} [rotate] reset secret even if the secret exists
96
- * @public
97
- */
98
- ensureCsrfSecret(rotate) {
99
- const csrfSecret = this.getCsrfSecret();
100
- if (csrfSecret && !rotate) {
101
- return;
102
- }
103
- debug('ensure csrf secret, exists: %s, rotate; %s', csrfSecret, rotate);
104
- const secret = tokens.secretSync();
105
- this[NEW_CSRF_SECRET] = secret;
106
- let { useSession, sessionName, cookieDomain, cookieName: cookieNames, cookieOptions, } = this.app.config.security.csrf;
107
- if (useSession) {
108
- // TODO(fengmk2): need to refactor egg-session plugin to support ctx.session type define
109
- this.session[sessionName] = secret;
110
- }
111
- else {
112
- if (typeof cookieDomain === 'function') {
113
- cookieDomain = cookieDomain(this);
114
- }
115
- const cookieOpts = {
116
- domain: cookieDomain,
117
- ...cookieOptions,
118
- };
119
- // cookieName support array. so we can change csrf cookie name smoothly
120
- if (!Array.isArray(cookieNames)) {
121
- cookieNames = [cookieNames];
122
- }
123
- for (const cookieName of cookieNames) {
124
- this.cookies.set(cookieName, secret, cookieOpts);
125
- }
126
- }
127
- }
128
- getInputToken() {
129
- const { headerName, bodyName, queryName } = this.app.config.security.csrf;
130
- // try order: query, body, header
131
- const token = findToken(this.request.query, queryName) ||
132
- findToken(this.request.body, bodyName) ||
133
- (headerName && this.request.get(headerName));
134
- debug('get token: %j, secret: %j', token, this.getCsrfSecret());
135
- return token;
136
- }
137
- /**
138
- * rotate csrf secret exists in session or cookie.
139
- * must rotate the secret when user login
140
- * @public
141
- */
142
- rotateCsrfSecret() {
143
- if (!this[NEW_CSRF_SECRET] && this.getCsrfSecret()) {
144
- this.ensureCsrfSecret(true);
145
- }
146
- }
147
- /**
148
- * assert csrf token/referer is present
149
- * @public
150
- */
151
- assertCsrf() {
152
- if (utils.checkIfIgnore(this.app.config.security.csrf, this)) {
153
- debug('%s, ignore by csrf options', this.path);
154
- return;
155
- }
156
- const { type } = this.app.config.security.csrf;
157
- let message;
158
- const messages = [];
159
- switch (type) {
160
- case 'ctoken':
161
- message = this.csrfCtokenCheck();
162
- if (message)
163
- this.throw(403, message);
164
- break;
165
- case 'referer':
166
- message = this.csrfRefererCheck();
167
- if (message)
168
- this.throw(403, message);
169
- break;
170
- case 'all':
171
- message = this.csrfCtokenCheck();
172
- if (message)
173
- this.throw(403, message);
174
- message = this.csrfRefererCheck();
175
- if (message)
176
- this.throw(403, message);
177
- break;
178
- case 'any':
179
- message = this.csrfCtokenCheck();
180
- if (!message)
181
- return;
182
- messages.push(message);
183
- message = this.csrfRefererCheck();
184
- if (!message)
185
- return;
186
- messages.push(message);
187
- this.throw(403, `both ctoken and referer check error: ${messages.join(', ')}`);
188
- break;
189
- default:
190
- // @oxlint-disable-next-line Invalid type "never" of template literal expression
191
- this.throw(`invalid type ${type}`);
192
- }
193
- }
194
- csrfCtokenCheck() {
195
- const csrfSecret = this.getCsrfSecret();
196
- if (!csrfSecret) {
197
- debug('missing csrf token');
198
- this.logCsrfNotice('missing csrf token');
199
- return 'missing csrf token';
200
- }
201
- const token = this.getInputToken();
202
- // AJAX requests get csrf token from cookie, in this situation token will equal to secret
203
- // synchronize form requests' token always changing to protect against BREACH attacks
204
- if (token !== csrfSecret && !tokens.verify(csrfSecret, token)) {
205
- debug('verify secret and token error');
206
- this.logCsrfNotice('invalid csrf token');
207
- const { rotateWhenInvalid } = this.app.config.security.csrf;
208
- if (rotateWhenInvalid) {
209
- this.rotateCsrfSecret();
210
- }
211
- return 'invalid csrf token';
212
- }
213
- }
214
- csrfRefererCheck() {
215
- const { refererWhiteList } = this.app.config.security.csrf;
216
- // check Origin/Referer headers
217
- const referer = (this.headers.referer ?? this.headers.origin ?? '').toLowerCase();
218
- if (!referer) {
219
- debug('missing csrf referer or origin');
220
- this.logCsrfNotice('missing csrf referer or origin');
221
- return 'missing csrf referer or origin';
222
- }
223
- const host = utils.getFromUrl(referer, 'host');
224
- const domainList = refererWhiteList.concat(this.host);
225
- if (!host || !utils.isSafeDomain(host, domainList)) {
226
- debug('verify referer or origin error');
227
- this.logCsrfNotice('invalid csrf referer or origin');
228
- return 'invalid csrf referer or origin';
229
- }
230
- }
231
- logCsrfNotice(msg) {
232
- if (this.app.config.env === 'local') {
233
- this.logger.warn(`${msg}. See https://eggjs.org/zh-CN/core/security/#%E5%AE%89%E5%85%A8%E5%A8%81%E8%83%81-csrf-%E7%9A%84%E9%98%B2%E8%8C%83`);
234
- }
235
- }
236
- async safeCurl(url, options) {
237
- return await this.app.safeCurl(url, options);
238
- }
239
- unsafeRedirect(url, alt) {
240
- this.response.unsafeRedirect(url, alt);
241
- }
242
- }
243
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGV4dC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9hcHAvZXh0ZW5kL2NvbnRleHQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUVyQyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDM0MsT0FBTyxNQUFNLE1BQU0sTUFBTSxDQUFDO0FBQzFCLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxLQUFLLENBQUM7QUFFOUIsT0FBTyxLQUFLLEtBQUssTUFBTSxvQkFBb0IsQ0FBQztBQUs1QyxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsaUNBQWlDLENBQUMsQ0FBQztBQUUxRCxNQUFNLE1BQU0sR0FBRyxJQUFJLE1BQU0sRUFBRSxDQUFDO0FBRTVCLE1BQU0sWUFBWSxHQUFHLE1BQU0sQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO0FBQ3pELE1BQU0sZUFBZSxHQUFHLE1BQU0sQ0FBQyw4QkFBOEIsQ0FBQyxDQUFDO0FBQy9ELE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO0FBQ3ZELE1BQU0sZ0JBQWdCLEdBQUcsTUFBTSxDQUFDLCtCQUErQixDQUFDLENBQUM7QUFFakUsU0FBUyxTQUFTLENBQUMsR0FBMkIsRUFBRSxJQUF1QjtJQUNyRSxJQUFJLENBQUMsR0FBRztRQUFFLE9BQU87SUFDakIsSUFBSSxDQUFDLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNO1FBQUUsT0FBTztJQUNsQyxJQUFJLE9BQU8sSUFBSSxLQUFLLFFBQVE7UUFBRSxPQUFPLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMvQyxLQUFLLE1BQU0sR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDO1FBQ3ZCLElBQUksR0FBRyxDQUFDLEdBQUcsQ0FBQztZQUFFLE9BQU8sR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ2hD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
20
+ var SecurityContext = class extends Context {
21
+ get securityOptions() {
22
+ if (!this[SECURITY_OPTIONS]) this[SECURITY_OPTIONS] = {};
23
+ return this[SECURITY_OPTIONS];
24
+ }
25
+ /**
26
+ * Check whether the specific `domain` is in / matches the whiteList or not.
27
+ * @param {string} domain The assigned domain.
28
+ * @param {Array<string>} [customWhiteList] The custom white list for domain.
29
+ * @return {boolean} If the domain is in / matches the whiteList, return true;
30
+ * otherwise false.
31
+ */
32
+ isSafeDomain(domain, customWhiteList) {
33
+ const domainWhiteList = customWhiteList && customWhiteList.length > 0 ? customWhiteList : this.app.config.security.domainWhiteList;
34
+ return isSafeDomain(domain, domainWhiteList);
35
+ }
36
+ get nonce() {
37
+ if (!this[NONCE_CACHE]) this[NONCE_CACHE] = nanoid(16);
38
+ return this[NONCE_CACHE];
39
+ }
40
+ /**
41
+ * get csrf token, general use in template
42
+ * @return {String} csrf token
43
+ * @public
44
+ */
45
+ get csrf() {
46
+ const secret = this[NEW_CSRF_SECRET] || this.getCsrfSecret();
47
+ debug("get csrf token, NEW_CSRF_SECRET: %s, _CSRF_SECRET: %s", this[NEW_CSRF_SECRET], this.getCsrfSecret());
48
+ return secret ? tokens.create(secret) : "";
49
+ }
50
+ /**
51
+ * get csrf secret from session or cookie
52
+ * @return {String} csrf secret
53
+ * @private
54
+ */
55
+ getCsrfSecret() {
56
+ if (this[_CSRF_SECRET]) return this[_CSRF_SECRET];
57
+ let { useSession, sessionName, cookieName: cookieNames, cookieOptions } = this.app.config.security.csrf;
58
+ if (useSession) this[_CSRF_SECRET] = this.session[sessionName] || "";
59
+ else {
60
+ if (!Array.isArray(cookieNames)) cookieNames = [cookieNames];
61
+ for (const cookieName of cookieNames) {
62
+ this[_CSRF_SECRET] = this.cookies.get(cookieName, { signed: cookieOptions.signed }) || "";
63
+ if (this[_CSRF_SECRET]) break;
64
+ }
65
+ }
66
+ return this[_CSRF_SECRET];
67
+ }
68
+ /**
69
+ * ensure csrf secret exists in session or cookie.
70
+ * @param {Boolean} [rotate] reset secret even if the secret exists
71
+ * @public
72
+ */
73
+ ensureCsrfSecret(rotate) {
74
+ const csrfSecret = this.getCsrfSecret();
75
+ if (csrfSecret && !rotate) return;
76
+ debug("ensure csrf secret, exists: %s, rotate; %s", csrfSecret, rotate);
77
+ const secret = tokens.secretSync();
78
+ this[NEW_CSRF_SECRET] = secret;
79
+ let { useSession, sessionName, cookieDomain, cookieName: cookieNames, cookieOptions } = this.app.config.security.csrf;
80
+ if (useSession) this.session[sessionName] = secret;
81
+ else {
82
+ if (typeof cookieDomain === "function") cookieDomain = cookieDomain(this);
83
+ const cookieOpts = {
84
+ domain: cookieDomain,
85
+ ...cookieOptions
86
+ };
87
+ if (!Array.isArray(cookieNames)) cookieNames = [cookieNames];
88
+ for (const cookieName of cookieNames) this.cookies.set(cookieName, secret, cookieOpts);
89
+ }
90
+ }
91
+ getInputToken() {
92
+ const { headerName, bodyName, queryName } = this.app.config.security.csrf;
93
+ const token = findToken(this.request.query, queryName) || findToken(this.request.body, bodyName) || headerName && this.request.get(headerName);
94
+ debug("get token: %j, secret: %j", token, this.getCsrfSecret());
95
+ return token;
96
+ }
97
+ /**
98
+ * rotate csrf secret exists in session or cookie.
99
+ * must rotate the secret when user login
100
+ * @public
101
+ */
102
+ rotateCsrfSecret() {
103
+ if (!this[NEW_CSRF_SECRET] && this.getCsrfSecret()) this.ensureCsrfSecret(true);
104
+ }
105
+ /**
106
+ * assert csrf token/referer is present
107
+ * @public
108
+ */
109
+ assertCsrf() {
110
+ if (checkIfIgnore(this.app.config.security.csrf, this)) {
111
+ debug("%s, ignore by csrf options", this.path);
112
+ return;
113
+ }
114
+ const { type } = this.app.config.security.csrf;
115
+ let message;
116
+ const messages = [];
117
+ switch (type) {
118
+ case "ctoken":
119
+ message = this.csrfCtokenCheck();
120
+ if (message) this.throw(403, message);
121
+ break;
122
+ case "referer":
123
+ message = this.csrfRefererCheck();
124
+ if (message) this.throw(403, message);
125
+ break;
126
+ case "all":
127
+ message = this.csrfCtokenCheck();
128
+ if (message) this.throw(403, message);
129
+ message = this.csrfRefererCheck();
130
+ if (message) this.throw(403, message);
131
+ break;
132
+ case "any":
133
+ message = this.csrfCtokenCheck();
134
+ if (!message) return;
135
+ messages.push(message);
136
+ message = this.csrfRefererCheck();
137
+ if (!message) return;
138
+ messages.push(message);
139
+ this.throw(403, `both ctoken and referer check error: ${messages.join(", ")}`);
140
+ break;
141
+ default: this.throw(`invalid type ${type}`);
142
+ }
143
+ }
144
+ csrfCtokenCheck() {
145
+ const csrfSecret = this.getCsrfSecret();
146
+ if (!csrfSecret) {
147
+ debug("missing csrf token");
148
+ this.logCsrfNotice("missing csrf token");
149
+ return "missing csrf token";
150
+ }
151
+ const token = this.getInputToken();
152
+ if (token !== csrfSecret && !tokens.verify(csrfSecret, token)) {
153
+ debug("verify secret and token error");
154
+ this.logCsrfNotice("invalid csrf token");
155
+ const { rotateWhenInvalid } = this.app.config.security.csrf;
156
+ if (rotateWhenInvalid) this.rotateCsrfSecret();
157
+ return "invalid csrf token";
158
+ }
159
+ }
160
+ csrfRefererCheck() {
161
+ const { refererWhiteList } = this.app.config.security.csrf;
162
+ const referer = (this.headers.referer ?? this.headers.origin ?? "").toLowerCase();
163
+ if (!referer) {
164
+ debug("missing csrf referer or origin");
165
+ this.logCsrfNotice("missing csrf referer or origin");
166
+ return "missing csrf referer or origin";
167
+ }
168
+ const host = getFromUrl(referer, "host");
169
+ const domainList = refererWhiteList.concat(this.host);
170
+ if (!host || !isSafeDomain(host, domainList)) {
171
+ debug("verify referer or origin error");
172
+ this.logCsrfNotice("invalid csrf referer or origin");
173
+ return "invalid csrf referer or origin";
174
+ }
175
+ }
176
+ logCsrfNotice(msg) {
177
+ if (this.app.config.env === "local") this.logger.warn(`${msg}. See https://eggjs.org/zh-CN/core/security/#%E5%AE%89%E5%85%A8%E5%A8%81%E8%83%81-csrf-%E7%9A%84%E9%98%B2%E8%8C%83`);
178
+ }
179
+ async safeCurl(url, options) {
180
+ return await this.app.safeCurl(url, options);
181
+ }
182
+ unsafeRedirect(url, alt) {
183
+ this.response.unsafeRedirect(url, alt);
184
+ }
185
+ };
186
+
187
+ //#endregion
188
+ export { SecurityContext as default };
@@ -1,3 +1,6 @@
1
- import helpers from '../../lib/helper/index.ts';
1
+ import helpers from "../../lib/helper/index.js";
2
+
3
+ //#region src/app/extend/helper.d.ts
2
4
  declare const securityHelpers: typeof helpers;
3
- export default securityHelpers;
5
+ //#endregion
6
+ export { securityHelpers as default };
@@ -1,6 +1,8 @@
1
- import helpers from "../../lib/helper/index.js";
2
- const securityHelpers = {
3
- ...helpers,
4
- };
5
- export default securityHelpers;
6
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVscGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2FwcC9leHRlbmQvaGVscGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sT0FBTyxNQUFNLDJCQUEyQixDQUFDO0FBRWhELE1BQU0sZUFBZSxHQUFtQjtJQUN0QyxHQUFHLE9BQU87Q0FDWCxDQUFDO0FBRUYsZUFBZSxlQUFlLENBQUMifQ==
1
+ import helper_default$1 from "../../lib/helper/index.js";
2
+
3
+ //#region src/app/extend/helper.ts
4
+ const securityHelpers = { ...helper_default$1 };
5
+ var helper_default = securityHelpers;
6
+
7
+ //#endregion
8
+ export { helper_default as default };
@@ -1,35 +1,39 @@
1
- import { Response } from 'egg';
2
- import SecurityContext from './context.ts';
3
- export default class SecurityResponse extends Response {
4
- ctx: SecurityContext;
5
- /**
6
- * This is an unsafe redirection, and we WON'T check if the
7
- * destination url is safe or not.
8
- * Please DO NOT use this method unless in some very special cases,
9
- * otherwise there may be security vulnerabilities.
10
- *
11
- * @function Response#unsafeRedirect
12
- * @param {String} url URL to forward
13
- * @example
14
- * ```js
15
- * ctx.response.unsafeRedirect('http://www.domain.com');
16
- * ctx.unsafeRedirect('http://www.domain.com');
17
- * ```
18
- */
19
- unsafeRedirect(url: string, alt?: string): void;
20
- /**
21
- * A safe redirection, and we'll check if the URL is in
22
- * a safe domain or not.
23
- * We've overridden the default Koa's implementation by adding a
24
- * white list as the filter for that.
25
- *
26
- * @function Response#redirect
27
- * @param {String} url URL to forward
28
- * @example
29
- * ```js
30
- * ctx.response.redirect('/login');
31
- * ctx.redirect('/login');
32
- * ```
33
- */
34
- redirect(url: string, alt?: string): void;
1
+ import SecurityContext from "./context.js";
2
+ import { Response } from "egg";
3
+
4
+ //#region src/app/extend/response.d.ts
5
+ declare class SecurityResponse extends Response {
6
+ ctx: SecurityContext;
7
+ /**
8
+ * This is an unsafe redirection, and we WON'T check if the
9
+ * destination url is safe or not.
10
+ * Please DO NOT use this method unless in some very special cases,
11
+ * otherwise there may be security vulnerabilities.
12
+ *
13
+ * @function Response#unsafeRedirect
14
+ * @param {String} url URL to forward
15
+ * @example
16
+ * ```js
17
+ * ctx.response.unsafeRedirect('http://www.domain.com');
18
+ * ctx.unsafeRedirect('http://www.domain.com');
19
+ * ```
20
+ */
21
+ unsafeRedirect(url: string, alt?: string): void;
22
+ /**
23
+ * A safe redirection, and we'll check if the URL is in
24
+ * a safe domain or not.
25
+ * We've overridden the default Koa's implementation by adding a
26
+ * white list as the filter for that.
27
+ *
28
+ * @function Response#redirect
29
+ * @param {String} url URL to forward
30
+ * @example
31
+ * ```js
32
+ * ctx.response.redirect('/login');
33
+ * ctx.redirect('/login');
34
+ * ```
35
+ */
36
+ redirect(url: string, alt?: string): void;
35
37
  }
38
+ //#endregion
39
+ export { SecurityResponse as default };