@eggjs/security 5.0.0-beta.20 → 5.0.0-beta.22
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.
- package/dist/agent.d.ts +5 -9
- package/dist/agent.js +11 -15
- package/dist/app/extend/agent.d.ts +4 -9
- package/dist/app/extend/agent.js +8 -12
- package/dist/app/extend/application.d.ts +8 -4
- package/dist/app/extend/application.js +32 -4
- package/dist/app/extend/context.d.ts +58 -4
- package/dist/app/extend/context.js +244 -4
- package/dist/app/extend/helper.d.ts +10 -22
- package/dist/app/extend/helper.js +5 -17
- package/dist/app/extend/response.d.ts +35 -4
- package/dist/app/extend/response.js +83 -5
- package/dist/app/middleware/securities.d.ts +4 -8
- package/dist/app/middleware/securities.js +52 -49
- package/dist/app.d.ts +5 -9
- package/dist/app.js +26 -24
- package/dist/config/config.default.d.ts +867 -2
- package/dist/config/config.default.js +366 -3
- package/dist/config/config.local.d.ts +2 -5
- package/dist/config/config.local.js +8 -5
- package/dist/index.d.ts +4 -5
- package/dist/index.js +5 -8
- package/dist/lib/extend/safe_curl.d.ts +16 -3
- package/dist/lib/extend/safe_curl.js +25 -3
- package/dist/lib/helper/cliFilter.d.ts +4 -2
- package/dist/lib/helper/cliFilter.js +17 -3
- package/dist/lib/helper/escape.d.ts +2 -2
- package/dist/lib/helper/escape.js +3 -3
- package/dist/lib/helper/escapeShellArg.d.ts +1 -2
- package/dist/lib/helper/escapeShellArg.js +5 -3
- package/dist/lib/helper/escapeShellCmd.d.ts +1 -2
- package/dist/lib/helper/escapeShellCmd.js +14 -3
- package/dist/lib/helper/index.d.ts +19 -22
- package/dist/lib/helper/index.js +21 -13
- package/dist/lib/helper/shtml.d.ts +2 -2
- package/dist/lib/helper/shtml.js +69 -4
- package/dist/lib/helper/sjs.d.ts +4 -2
- package/dist/lib/helper/sjs.js +49 -3
- package/dist/lib/helper/sjson.d.ts +1 -2
- package/dist/lib/helper/sjson.js +39 -4
- package/dist/lib/helper/spath.d.ts +5 -2
- package/dist/lib/helper/spath.js +25 -3
- package/dist/lib/helper/surl.d.ts +2 -2
- package/dist/lib/helper/surl.js +30 -3
- package/dist/lib/middlewares/csp.d.ts +3 -6
- package/dist/lib/middlewares/csp.js +57 -4
- package/dist/lib/middlewares/csrf.d.ts +3 -6
- package/dist/lib/middlewares/csrf.js +37 -4
- package/dist/lib/middlewares/dta.d.ts +2 -5
- package/dist/lib/middlewares/dta.js +12 -4
- package/dist/lib/middlewares/hsts.d.ts +3 -6
- package/dist/lib/middlewares/hsts.js +21 -4
- package/dist/lib/middlewares/index.d.ts +11 -16
- package/dist/lib/middlewares/index.js +23 -14
- package/dist/lib/middlewares/methodnoallow.d.ts +2 -5
- package/dist/lib/middlewares/methodnoallow.js +20 -3
- package/dist/lib/middlewares/noopen.d.ts +3 -6
- package/dist/lib/middlewares/noopen.js +15 -4
- package/dist/lib/middlewares/nosniff.d.ts +3 -6
- package/dist/lib/middlewares/nosniff.js +28 -4
- package/dist/lib/middlewares/referrerPolicy.d.ts +3 -6
- package/dist/lib/middlewares/referrerPolicy.js +35 -4
- package/dist/lib/middlewares/xframe.d.ts +3 -6
- package/dist/lib/middlewares/xframe.js +17 -4
- package/dist/lib/middlewares/xssProtection.d.ts +3 -6
- package/dist/lib/middlewares/xssProtection.js +14 -4
- package/dist/lib/utils.d.ts +12 -17
- package/dist/lib/utils.js +192 -3
- package/dist/types.d.ts +36 -3
- package/dist/types.js +2 -3
- package/package.json +6 -6
- package/dist/application-COC0mYEe.js +0 -32
- package/dist/application-n5bk2L_z.d.ts +0 -12
- package/dist/cliFilter-7BSD8Nc_.js +0 -18
- package/dist/cliFilter-DKZxCxSe.d.ts +0 -7
- package/dist/config.default-AcwQOAG0.js +0 -166
- package/dist/config.default-D8v08Vox.d.ts +0 -870
- package/dist/context-C-N1IY85.d.ts +0 -95
- package/dist/context-e-QJTKfq.js +0 -191
- package/dist/csp-BW5AJd_f.js +0 -46
- package/dist/csrf-9aSLHiby.js +0 -33
- package/dist/dta-DVAKEpJ3.js +0 -13
- package/dist/escape-Dex_Pk9e.d.ts +0 -2
- package/dist/escape-p8-cW8c_.js +0 -7
- package/dist/escapeShellArg-BnzDicAC.d.ts +0 -4
- package/dist/escapeShellArg-C0v1ZeCl.js +0 -7
- package/dist/escapeShellCmd-CkAdyhtO.js +0 -15
- package/dist/escapeShellCmd-DQZZIHde.d.ts +0 -4
- package/dist/helper-DylzfQ_5.js +0 -25
- package/dist/hsts-CWMKNTEh.js +0 -19
- package/dist/methodnoallow-BAZONArS.js +0 -15
- package/dist/middlewares-CkQjv8t0.js +0 -27
- package/dist/noopen-C3jUBwoH.js +0 -17
- package/dist/nosniff-CcLkhX2I.js +0 -27
- package/dist/referrerPolicy-D4Uafq6c.js +0 -31
- package/dist/response-BFnHAJrV.js +0 -69
- package/dist/safe_curl-UlViaxoF.js +0 -19
- package/dist/safe_curl-mqZZv_YQ.d.ts +0 -20
- package/dist/shtml-CAquTzgV.d.ts +0 -6
- package/dist/shtml-CgF4kOx-.js +0 -53
- package/dist/sjs-Cbmkk5xS.js +0 -36
- package/dist/sjs-QZIJYS71.d.ts +0 -7
- package/dist/sjson-BetFnVR6.js +0 -32
- package/dist/sjson-O-vKJPws.d.ts +0 -4
- package/dist/spath-Bu9sy6Kz.js +0 -16
- package/dist/spath-DseDPHxf.d.ts +0 -7
- package/dist/surl-ClleTea7.js +0 -25
- package/dist/surl-JV70X_RZ.d.ts +0 -6
- package/dist/types-BZR2U30p.d.ts +0 -38
- package/dist/types-DnJpiSJb.js +0 -1
- package/dist/utils-Cajs5P8M.js +0 -127
- package/dist/xframe-q9fEZkVI.js +0 -18
- package/dist/xssProtection-D5QsHX-e.js +0 -17
package/dist/agent.d.ts
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
constructor(agent: Agent);
|
|
7
|
-
configWillLoad(): Promise<void>;
|
|
1
|
+
import type { ILifecycleBoot, Agent } from 'egg';
|
|
2
|
+
export default class AgentBoot implements ILifecycleBoot {
|
|
3
|
+
private readonly agent;
|
|
4
|
+
constructor(agent: Agent);
|
|
5
|
+
configWillLoad(): Promise<void>;
|
|
8
6
|
}
|
|
9
|
-
//#endregion
|
|
10
|
-
export { AgentBoot as default };
|
package/dist/agent.js
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import { preprocessConfig } from "./utils
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
//#endregion
|
|
15
|
-
export { AgentBoot as default };
|
|
1
|
+
import { preprocessConfig } from "./lib/utils.js";
|
|
2
|
+
export default class AgentBoot {
|
|
3
|
+
agent;
|
|
4
|
+
constructor(agent) {
|
|
5
|
+
this.agent = agent;
|
|
6
|
+
}
|
|
7
|
+
async configWillLoad() {
|
|
8
|
+
preprocessConfig(this.agent.config.security);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWdlbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvYWdlbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFbEQsTUFBTSxDQUFDLE9BQU8sT0FBTyxTQUFTO0lBQ1gsS0FBSyxDQUFDO0lBRXZCLFlBQVksS0FBWTtRQUN0QixJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztJQUNyQixDQUFDO0lBRUQsS0FBSyxDQUFDLGNBQWM7UUFDbEIsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDL0MsQ0FBQztDQUNGIn0=
|
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
//#region src/app/extend/agent.d.ts
|
|
6
|
-
declare class SecurityAgent extends Agent {
|
|
7
|
-
safeCurl<T = any>(url: HttpClientRequestURL, options?: HttpClientOptions): Promise<HttpClientResponse<T>>;
|
|
1
|
+
import { Agent } from 'egg';
|
|
2
|
+
import { type HttpClientRequestURL, type HttpClientOptions, type HttpClientResponse } from '../../lib/extend/safe_curl.ts';
|
|
3
|
+
export default class SecurityAgent extends Agent {
|
|
4
|
+
safeCurl<T = any>(url: HttpClientRequestURL, options?: HttpClientOptions): Promise<HttpClientResponse<T>>;
|
|
8
5
|
}
|
|
9
|
-
//#endregion
|
|
10
|
-
export { SecurityAgent as default };
|
package/dist/app/extend/agent.js
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
//#endregion
|
|
12
|
-
export { SecurityAgent as default };
|
|
1
|
+
import { Agent } from 'egg';
|
|
2
|
+
import { safeCurlForApplication, } from "../../lib/extend/safe_curl.js";
|
|
3
|
+
export default class SecurityAgent extends Agent {
|
|
4
|
+
async safeCurl(url, options) {
|
|
5
|
+
return await safeCurlForApplication(this, url, options);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWdlbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBwL2V4dGVuZC9hZ2VudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sS0FBSyxDQUFDO0FBRTVCLE9BQU8sRUFDTCxzQkFBc0IsR0FJdkIsTUFBTSwrQkFBK0IsQ0FBQztBQUV2QyxNQUFNLENBQUMsT0FBTyxPQUFPLGFBQWMsU0FBUSxLQUFLO0lBQzlDLEtBQUssQ0FBQyxRQUFRLENBQVUsR0FBeUIsRUFBRSxPQUEyQjtRQUM1RSxPQUFPLE1BQU0sc0JBQXNCLENBQUksSUFBSSxFQUFFLEdBQUcsRUFBRSxPQUFPLENBQUMsQ0FBQztJQUM3RCxDQUFDO0NBQ0YifQ==
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { Application } from 'egg';
|
|
2
|
+
import { type HttpClientRequestURL, type HttpClientOptions, type HttpClientResponse } from '../../lib/extend/safe_curl.ts';
|
|
3
|
+
export default class SecurityApplication extends Application {
|
|
4
|
+
injectCsrf(html: string): string;
|
|
5
|
+
injectNonce(html: string): string;
|
|
6
|
+
injectHijackingDefense(html: string): string;
|
|
7
|
+
safeCurl<T = any>(url: HttpClientRequestURL, options?: HttpClientOptions): Promise<HttpClientResponse<T>>;
|
|
8
|
+
}
|
|
@@ -1,4 +1,32 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { Application } from 'egg';
|
|
2
|
+
import { safeCurlForApplication, } from "../../lib/extend/safe_curl.js";
|
|
3
|
+
const INPUT_CSRF = '\r\n<input type="hidden" name="_csrf" value="{{ctx.csrf}}" /></form>';
|
|
4
|
+
const INJECTION_DEFENSE = '<!--for injection--><!--</html>--><!--for injection-->';
|
|
5
|
+
export default class SecurityApplication extends Application {
|
|
6
|
+
injectCsrf(html) {
|
|
7
|
+
html = html.replace(/(<form.*?>)([\s\S]*?)<\/form>/gi, (_, $1, $2) => {
|
|
8
|
+
const match = $2;
|
|
9
|
+
if (match.indexOf('name="_csrf"') !== -1 || match.indexOf("name='_csrf'") !== -1) {
|
|
10
|
+
return $1 + match + '</form>';
|
|
11
|
+
}
|
|
12
|
+
return $1 + match + INPUT_CSRF;
|
|
13
|
+
});
|
|
14
|
+
return html;
|
|
15
|
+
}
|
|
16
|
+
injectNonce(html) {
|
|
17
|
+
html = html.replace(/<script(.*?)>([\s\S]*?)<\/script[^>]*?>/gi, (_, $1, $2) => {
|
|
18
|
+
if (!$1.includes('nonce=')) {
|
|
19
|
+
$1 += ' nonce="{{ctx.nonce}}"';
|
|
20
|
+
}
|
|
21
|
+
return '<script' + $1 + '>' + $2 + '</script>';
|
|
22
|
+
});
|
|
23
|
+
return html;
|
|
24
|
+
}
|
|
25
|
+
injectHijackingDefense(html) {
|
|
26
|
+
return INJECTION_DEFENSE + html + INJECTION_DEFENSE;
|
|
27
|
+
}
|
|
28
|
+
async safeCurl(url, options) {
|
|
29
|
+
return await safeCurlForApplication(this, url, options);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwbGljYXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBwL2V4dGVuZC9hcHBsaWNhdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sS0FBSyxDQUFDO0FBRWxDLE9BQU8sRUFDTCxzQkFBc0IsR0FJdkIsTUFBTSwrQkFBK0IsQ0FBQztBQUV2QyxNQUFNLFVBQVUsR0FBRyxzRUFBc0UsQ0FBQztBQUMxRixNQUFNLGlCQUFpQixHQUFHLHdEQUF3RCxDQUFDO0FBRW5GLE1BQU0sQ0FBQyxPQUFPLE9BQU8sbUJBQW9CLFNBQVEsV0FBVztJQUMxRCxVQUFVLENBQUMsSUFBWTtRQUNyQixJQUFJLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxpQ0FBaUMsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUU7WUFDbkUsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDO1lBQ2pCLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUM7Z0JBQ2pGLE9BQU8sRUFBRSxHQUFHLEtBQUssR0FBRyxTQUFTLENBQUM7WUFDaEMsQ0FBQztZQUNELE9BQU8sRUFBRSxHQUFHLEtBQUssR0FBRyxVQUFVLENBQUM7UUFDakMsQ0FBQyxDQUFDLENBQUM7UUFDSCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRCxXQUFXLENBQUMsSUFBWTtRQUN0QixJQUFJLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQywyQ0FBMkMsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUU7WUFDN0UsSUFBSSxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztnQkFDM0IsRUFBRSxJQUFJLHdCQUF3QixDQUFDO1lBQ2pDLENBQUM7WUFDRCxPQUFPLFNBQVMsR0FBRyxFQUFFLEdBQUcsR0FBRyxHQUFHLEVBQUUsR0FBRyxXQUFXLENBQUM7UUFDakQsQ0FBQyxDQUFDLENBQUM7UUFDSCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRCxzQkFBc0IsQ0FBQyxJQUFZO1FBQ2pDLE9BQU8saUJBQWlCLEdBQUcsSUFBSSxHQUFHLGlCQUFpQixDQUFDO0lBQ3RELENBQUM7SUFFRCxLQUFLLENBQUMsUUFBUSxDQUFVLEdBQXlCLEVBQUUsT0FBMkI7UUFDNUUsT0FBTyxNQUFNLHNCQUFzQixDQUFJLElBQUksRUFBRSxHQUFHLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDN0QsQ0FBQztDQUNGIn0=
|
|
@@ -1,4 +1,58 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
1
|
+
import { Context } from 'egg';
|
|
2
|
+
import type { HttpClientRequestURL, HttpClientOptions, HttpClientResponse } from '../../lib/extend/safe_curl.ts';
|
|
3
|
+
import type { SecurityConfig } from '../../config/config.default.ts';
|
|
4
|
+
import type SecurityResponse from './response.ts';
|
|
5
|
+
declare const CSRF_SECRET: unique symbol;
|
|
6
|
+
declare const LOG_CSRF_NOTICE: unique symbol;
|
|
7
|
+
declare const INPUT_TOKEN: unique symbol;
|
|
8
|
+
declare const CSRF_REFERER_CHECK: unique symbol;
|
|
9
|
+
declare const CSRF_CTOKEN_CHECK: unique symbol;
|
|
10
|
+
export default class SecurityContext extends Context {
|
|
11
|
+
response: SecurityResponse;
|
|
12
|
+
get securityOptions(): Partial<SecurityConfig>;
|
|
13
|
+
/**
|
|
14
|
+
* Check whether the specific `domain` is in / matches the whiteList or not.
|
|
15
|
+
* @param {string} domain The assigned domain.
|
|
16
|
+
* @param {Array<string>} [customWhiteList] The custom white list for domain.
|
|
17
|
+
* @return {boolean} If the domain is in / matches the whiteList, return true;
|
|
18
|
+
* otherwise false.
|
|
19
|
+
*/
|
|
20
|
+
isSafeDomain(domain: string, customWhiteList?: string[]): boolean;
|
|
21
|
+
get nonce(): string;
|
|
22
|
+
/**
|
|
23
|
+
* get csrf token, general use in template
|
|
24
|
+
* @return {String} csrf token
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
get csrf(): string;
|
|
28
|
+
/**
|
|
29
|
+
* get csrf secret from session or cookie
|
|
30
|
+
* @return {String} csrf secret
|
|
31
|
+
* @private
|
|
32
|
+
*/
|
|
33
|
+
get [CSRF_SECRET](): string;
|
|
34
|
+
/**
|
|
35
|
+
* ensure csrf secret exists in session or cookie.
|
|
36
|
+
* @param {Boolean} [rotate] reset secret even if the secret exists
|
|
37
|
+
* @public
|
|
38
|
+
*/
|
|
39
|
+
ensureCsrfSecret(rotate?: boolean): void;
|
|
40
|
+
get [INPUT_TOKEN](): string;
|
|
41
|
+
/**
|
|
42
|
+
* rotate csrf secret exists in session or cookie.
|
|
43
|
+
* must rotate the secret when user login
|
|
44
|
+
* @public
|
|
45
|
+
*/
|
|
46
|
+
rotateCsrfSecret(): void;
|
|
47
|
+
/**
|
|
48
|
+
* assert csrf token/referer is present
|
|
49
|
+
* @public
|
|
50
|
+
*/
|
|
51
|
+
assertCsrf(): void;
|
|
52
|
+
[CSRF_CTOKEN_CHECK](): "missing csrf token" | "invalid csrf token" | undefined;
|
|
53
|
+
[CSRF_REFERER_CHECK](): "missing csrf referer or origin" | "invalid csrf referer or origin" | undefined;
|
|
54
|
+
[LOG_CSRF_NOTICE](msg: string): void;
|
|
55
|
+
safeCurl<T = any>(url: HttpClientRequestURL, options?: HttpClientOptions): Promise<HttpClientResponse<T>>;
|
|
56
|
+
unsafeRedirect(url: string, alt?: string): void;
|
|
57
|
+
}
|
|
58
|
+
export {};
|
|
@@ -1,4 +1,244 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
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');
|
|
7
|
+
const tokens = new Tokens();
|
|
8
|
+
const CSRF_SECRET = Symbol('egg-security#CSRF_SECRET');
|
|
9
|
+
const _CSRF_SECRET = Symbol('egg-security#_CSRF_SECRET');
|
|
10
|
+
const NEW_CSRF_SECRET = Symbol('egg-security#NEW_CSRF_SECRET');
|
|
11
|
+
const LOG_CSRF_NOTICE = Symbol('egg-security#LOG_CSRF_NOTICE');
|
|
12
|
+
const INPUT_TOKEN = Symbol('egg-security#INPUT_TOKEN');
|
|
13
|
+
const NONCE_CACHE = Symbol('egg-security#NONCE_CACHE');
|
|
14
|
+
const SECURITY_OPTIONS = Symbol('egg-security#SECURITY_OPTIONS');
|
|
15
|
+
const CSRF_REFERER_CHECK = Symbol('egg-security#CSRF_REFERER_CHECK');
|
|
16
|
+
const CSRF_CTOKEN_CHECK = Symbol('egg-security#CSRF_CTOKEN_CHECK');
|
|
17
|
+
function findToken(obj, keys) {
|
|
18
|
+
if (!obj)
|
|
19
|
+
return;
|
|
20
|
+
if (!keys || !keys.length)
|
|
21
|
+
return;
|
|
22
|
+
if (typeof keys === 'string')
|
|
23
|
+
return obj[keys];
|
|
24
|
+
for (const key of keys) {
|
|
25
|
+
if (obj[key])
|
|
26
|
+
return obj[key];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export default class SecurityContext extends Context {
|
|
30
|
+
get securityOptions() {
|
|
31
|
+
if (!this[SECURITY_OPTIONS]) {
|
|
32
|
+
this[SECURITY_OPTIONS] = {};
|
|
33
|
+
}
|
|
34
|
+
return this[SECURITY_OPTIONS];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Check whether the specific `domain` is in / matches the whiteList or not.
|
|
38
|
+
* @param {string} domain The assigned domain.
|
|
39
|
+
* @param {Array<string>} [customWhiteList] The custom white list for domain.
|
|
40
|
+
* @return {boolean} If the domain is in / matches the whiteList, return true;
|
|
41
|
+
* otherwise false.
|
|
42
|
+
*/
|
|
43
|
+
isSafeDomain(domain, customWhiteList) {
|
|
44
|
+
const domainWhiteList = customWhiteList && customWhiteList.length > 0 ? customWhiteList : this.app.config.security.domainWhiteList;
|
|
45
|
+
return utils.isSafeDomain(domain, domainWhiteList);
|
|
46
|
+
}
|
|
47
|
+
// Add nonce, random characters will be OK.
|
|
48
|
+
// https://w3c.github.io/webappsec/specs/content-security-policy/#nonce_source
|
|
49
|
+
get nonce() {
|
|
50
|
+
if (!this[NONCE_CACHE]) {
|
|
51
|
+
this[NONCE_CACHE] = nanoid(16);
|
|
52
|
+
}
|
|
53
|
+
return this[NONCE_CACHE];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* get csrf token, general use in template
|
|
57
|
+
* @return {String} csrf token
|
|
58
|
+
* @public
|
|
59
|
+
*/
|
|
60
|
+
get csrf() {
|
|
61
|
+
// csrfSecret can be rotate, use NEW_CSRF_SECRET first
|
|
62
|
+
const secret = this[NEW_CSRF_SECRET] || this[CSRF_SECRET];
|
|
63
|
+
debug('get csrf token, NEW_CSRF_SECRET: %s, _CSRF_SECRET: %s', this[NEW_CSRF_SECRET], this[CSRF_SECRET]);
|
|
64
|
+
// In order to protect against BREACH attacks,
|
|
65
|
+
// the token is not simply the secret;
|
|
66
|
+
// a random salt is prepended to the secret and used to scramble it.
|
|
67
|
+
// http://breachattack.com/
|
|
68
|
+
return secret ? tokens.create(secret) : '';
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* get csrf secret from session or cookie
|
|
72
|
+
* @return {String} csrf secret
|
|
73
|
+
* @private
|
|
74
|
+
*/
|
|
75
|
+
get [CSRF_SECRET]() {
|
|
76
|
+
if (this[_CSRF_SECRET]) {
|
|
77
|
+
return this[_CSRF_SECRET];
|
|
78
|
+
}
|
|
79
|
+
let { useSession, sessionName, cookieName: cookieNames, cookieOptions } = this.app.config.security.csrf;
|
|
80
|
+
// get secret from session or cookie
|
|
81
|
+
if (useSession) {
|
|
82
|
+
this[_CSRF_SECRET] = this.session[sessionName] || '';
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
// cookieName support array. so we can change csrf cookie name smoothly
|
|
86
|
+
if (!Array.isArray(cookieNames)) {
|
|
87
|
+
cookieNames = [cookieNames];
|
|
88
|
+
}
|
|
89
|
+
for (const cookieName of cookieNames) {
|
|
90
|
+
this[_CSRF_SECRET] = this.cookies.get(cookieName, { signed: cookieOptions.signed }) || '';
|
|
91
|
+
if (this[_CSRF_SECRET]) {
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return this[_CSRF_SECRET];
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* ensure csrf secret exists in session or cookie.
|
|
100
|
+
* @param {Boolean} [rotate] reset secret even if the secret exists
|
|
101
|
+
* @public
|
|
102
|
+
*/
|
|
103
|
+
ensureCsrfSecret(rotate) {
|
|
104
|
+
if (this[CSRF_SECRET] && !rotate)
|
|
105
|
+
return;
|
|
106
|
+
debug('ensure csrf secret, exists: %s, rotate; %s', this[CSRF_SECRET], rotate);
|
|
107
|
+
const secret = tokens.secretSync();
|
|
108
|
+
this[NEW_CSRF_SECRET] = secret;
|
|
109
|
+
let { useSession, sessionName, cookieDomain, cookieName: cookieNames, cookieOptions, } = this.app.config.security.csrf;
|
|
110
|
+
if (useSession) {
|
|
111
|
+
// TODO(fengmk2): need to refactor egg-session plugin to support ctx.session type define
|
|
112
|
+
this.session[sessionName] = secret;
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
if (typeof cookieDomain === 'function') {
|
|
116
|
+
cookieDomain = cookieDomain(this);
|
|
117
|
+
}
|
|
118
|
+
const cookieOpts = {
|
|
119
|
+
domain: cookieDomain,
|
|
120
|
+
...cookieOptions,
|
|
121
|
+
};
|
|
122
|
+
// cookieName support array. so we can change csrf cookie name smoothly
|
|
123
|
+
if (!Array.isArray(cookieNames)) {
|
|
124
|
+
cookieNames = [cookieNames];
|
|
125
|
+
}
|
|
126
|
+
for (const cookieName of cookieNames) {
|
|
127
|
+
this.cookies.set(cookieName, secret, cookieOpts);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
get [INPUT_TOKEN]() {
|
|
132
|
+
const { headerName, bodyName, queryName } = this.app.config.security.csrf;
|
|
133
|
+
// try order: query, body, header
|
|
134
|
+
const token = findToken(this.request.query, queryName) ||
|
|
135
|
+
findToken(this.request.body, bodyName) ||
|
|
136
|
+
(headerName && this.request.get(headerName));
|
|
137
|
+
debug('get token: %j, secret: %j', token, this[CSRF_SECRET]);
|
|
138
|
+
return token;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* rotate csrf secret exists in session or cookie.
|
|
142
|
+
* must rotate the secret when user login
|
|
143
|
+
* @public
|
|
144
|
+
*/
|
|
145
|
+
rotateCsrfSecret() {
|
|
146
|
+
if (!this[NEW_CSRF_SECRET] && this[CSRF_SECRET]) {
|
|
147
|
+
this.ensureCsrfSecret(true);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* assert csrf token/referer is present
|
|
152
|
+
* @public
|
|
153
|
+
*/
|
|
154
|
+
assertCsrf() {
|
|
155
|
+
if (utils.checkIfIgnore(this.app.config.security.csrf, this)) {
|
|
156
|
+
debug('%s, ignore by csrf options', this.path);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const { type } = this.app.config.security.csrf;
|
|
160
|
+
let message;
|
|
161
|
+
const messages = [];
|
|
162
|
+
switch (type) {
|
|
163
|
+
case 'ctoken':
|
|
164
|
+
message = this[CSRF_CTOKEN_CHECK]();
|
|
165
|
+
if (message)
|
|
166
|
+
this.throw(403, message);
|
|
167
|
+
break;
|
|
168
|
+
case 'referer':
|
|
169
|
+
message = this[CSRF_REFERER_CHECK]();
|
|
170
|
+
if (message)
|
|
171
|
+
this.throw(403, message);
|
|
172
|
+
break;
|
|
173
|
+
case 'all':
|
|
174
|
+
message = this[CSRF_CTOKEN_CHECK]();
|
|
175
|
+
if (message)
|
|
176
|
+
this.throw(403, message);
|
|
177
|
+
message = this[CSRF_REFERER_CHECK]();
|
|
178
|
+
if (message)
|
|
179
|
+
this.throw(403, message);
|
|
180
|
+
break;
|
|
181
|
+
case 'any':
|
|
182
|
+
message = this[CSRF_CTOKEN_CHECK]();
|
|
183
|
+
if (!message)
|
|
184
|
+
return;
|
|
185
|
+
messages.push(message);
|
|
186
|
+
message = this[CSRF_REFERER_CHECK]();
|
|
187
|
+
if (!message)
|
|
188
|
+
return;
|
|
189
|
+
messages.push(message);
|
|
190
|
+
this.throw(403, `both ctoken and referer check error: ${messages.join(', ')}`);
|
|
191
|
+
break;
|
|
192
|
+
default:
|
|
193
|
+
this.throw(`invalid type ${type}`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
[CSRF_CTOKEN_CHECK]() {
|
|
197
|
+
if (!this[CSRF_SECRET]) {
|
|
198
|
+
debug('missing csrf token');
|
|
199
|
+
this[LOG_CSRF_NOTICE]('missing csrf token');
|
|
200
|
+
return 'missing csrf token';
|
|
201
|
+
}
|
|
202
|
+
const token = this[INPUT_TOKEN];
|
|
203
|
+
// AJAX requests get csrf token from cookie, in this situation token will equal to secret
|
|
204
|
+
// synchronize form requests' token always changing to protect against BREACH attacks
|
|
205
|
+
if (token !== this[CSRF_SECRET] && !tokens.verify(this[CSRF_SECRET], token)) {
|
|
206
|
+
debug('verify secret and token error');
|
|
207
|
+
this[LOG_CSRF_NOTICE]('invalid csrf token');
|
|
208
|
+
const { rotateWhenInvalid } = this.app.config.security.csrf;
|
|
209
|
+
if (rotateWhenInvalid) {
|
|
210
|
+
this.rotateCsrfSecret();
|
|
211
|
+
}
|
|
212
|
+
return 'invalid csrf token';
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
[CSRF_REFERER_CHECK]() {
|
|
216
|
+
const { refererWhiteList } = this.app.config.security.csrf;
|
|
217
|
+
// check Origin/Referer headers
|
|
218
|
+
const referer = (this.headers.referer ?? this.headers.origin ?? '').toLowerCase();
|
|
219
|
+
if (!referer) {
|
|
220
|
+
debug('missing csrf referer or origin');
|
|
221
|
+
this[LOG_CSRF_NOTICE]('missing csrf referer or origin');
|
|
222
|
+
return 'missing csrf referer or origin';
|
|
223
|
+
}
|
|
224
|
+
const host = utils.getFromUrl(referer, 'host');
|
|
225
|
+
const domainList = refererWhiteList.concat(this.host);
|
|
226
|
+
if (!host || !utils.isSafeDomain(host, domainList)) {
|
|
227
|
+
debug('verify referer or origin error');
|
|
228
|
+
this[LOG_CSRF_NOTICE]('invalid csrf referer or origin');
|
|
229
|
+
return 'invalid csrf referer or origin';
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
[LOG_CSRF_NOTICE](msg) {
|
|
233
|
+
if (this.app.config.env === 'local') {
|
|
234
|
+
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`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
async safeCurl(url, options) {
|
|
238
|
+
return await this.app.safeCurl(url, options);
|
|
239
|
+
}
|
|
240
|
+
unsafeRedirect(url, alt) {
|
|
241
|
+
this.response.unsafeRedirect(url, alt);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGV4dC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9hcHAvZXh0ZW5kL2NvbnRleHQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUVyQyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDM0MsT0FBTyxNQUFNLE1BQU0sTUFBTSxDQUFDO0FBQzFCLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxLQUFLLENBQUM7QUFFOUIsT0FBTyxLQUFLLEtBQUssTUFBTSxvQkFBb0IsQ0FBQztBQUs1QyxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsaUNBQWlDLENBQUMsQ0FBQztBQUUxRCxNQUFNLE1BQU0sR0FBRyxJQUFJLE1BQU0sRUFBRSxDQUFDO0FBRTVCLE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO0FBQ3ZELE1BQU0sWUFBWSxHQUFHLE1BQU0sQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO0FBQ3pELE1BQU0sZUFBZSxHQUFHLE1BQU0sQ0FBQyw4QkFBOEIsQ0FBQyxDQUFDO0FBQy9ELE1BQU0sZUFBZSxHQUFHLE1BQU0sQ0FBQyw4QkFBOEIsQ0FBQyxDQUFDO0FBQy9ELE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO0FBQ3ZELE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO0FBQ3ZELE1BQU0sZ0JBQWdCLEdBQUcsTUFBTSxDQUFDLCtCQUErQixDQUFDLENBQUM7QUFDakUsTUFBTSxrQkFBa0IsR0FBRyxNQUFNLENBQUMsaUNBQWlDLENBQUMsQ0FBQztBQUNyRSxNQUFNLGlCQUFpQixHQUFHLE1BQU0sQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDO0FBRW5FLFNBQVMsU0FBUyxDQUFDLEdBQTJCLEVBQUUsSUFBdUI7SUFDckUsSUFBSSxDQUFDLEdBQUc7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
|
|
@@ -1,24 +1,12 @@
|
|
|
1
|
-
import { cliFilter } from "../../cliFilter-DKZxCxSe.js";
|
|
2
|
-
import { escapeShellArg } from "../../escapeShellArg-BnzDicAC.js";
|
|
3
|
-
import { escapeShellCmd } from "../../escapeShellCmd-DQZZIHde.js";
|
|
4
|
-
import { shtml } from "../../shtml-CAquTzgV.js";
|
|
5
|
-
import { escapeJavaScript } from "../../sjs-QZIJYS71.js";
|
|
6
|
-
import { jsonEscape } from "../../sjson-O-vKJPws.js";
|
|
7
|
-
import { pathFilter } from "../../spath-DseDPHxf.js";
|
|
8
|
-
import { surl } from "../../surl-JV70X_RZ.js";
|
|
9
|
-
import * as escape_html0 from "escape-html";
|
|
10
|
-
|
|
11
|
-
//#region src/app/extend/helper.d.ts
|
|
12
1
|
declare const _default: {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
2
|
+
cliFilter: typeof import("../../lib/helper/cliFilter.ts").default;
|
|
3
|
+
escape: typeof import("escape-html");
|
|
4
|
+
escapeShellArg: typeof import("../../lib/helper/escapeShellArg.ts").default;
|
|
5
|
+
escapeShellCmd: typeof import("../../lib/helper/escapeShellCmd.ts").default;
|
|
6
|
+
shtml: typeof import("../../lib/helper/shtml.ts").default;
|
|
7
|
+
sjs: typeof import("../../lib/helper/sjs.ts").default;
|
|
8
|
+
sjson: typeof import("../../lib/helper/sjson.ts").default;
|
|
9
|
+
spath: typeof import("../../lib/helper/spath.ts").default;
|
|
10
|
+
surl: typeof import("../../lib/helper/surl.ts").default;
|
|
22
11
|
};
|
|
23
|
-
|
|
24
|
-
export { _default as default };
|
|
12
|
+
export default _default;
|
|
@@ -1,17 +1,5 @@
|
|
|
1
|
-
import "../../
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import "../../shtml-CgF4kOx-.js";
|
|
7
|
-
import "../../sjs-Cbmkk5xS.js";
|
|
8
|
-
import "../../sjson-BetFnVR6.js";
|
|
9
|
-
import "../../spath-Bu9sy6Kz.js";
|
|
10
|
-
import "../../surl-ClleTea7.js";
|
|
11
|
-
import { helper_default as helper_default$1 } from "../../helper-DylzfQ_5.js";
|
|
12
|
-
|
|
13
|
-
//#region src/app/extend/helper.ts
|
|
14
|
-
var helper_default = { ...helper_default$1 };
|
|
15
|
-
|
|
16
|
-
//#endregion
|
|
17
|
-
export { helper_default as default };
|
|
1
|
+
import helpers from "../../lib/helper/index.js";
|
|
2
|
+
export default {
|
|
3
|
+
...helpers,
|
|
4
|
+
};
|
|
5
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVscGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2FwcC9leHRlbmQvaGVscGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sT0FBTyxNQUFNLDJCQUEyQixDQUFDO0FBRWhELGVBQWU7SUFDYixHQUFHLE9BQU87Q0FDWCxDQUFDIn0=
|
|
@@ -1,4 +1,35 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
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;
|
|
35
|
+
}
|