@eggjs/security 5.0.0-beta.20 → 5.0.0-beta.21
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
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
//#region src/lib/middlewares/nosniff.d.ts
|
|
1
|
+
import type { MiddlewareFunc } from 'egg';
|
|
2
|
+
import type { SecurityConfig } from '../../config/config.default.ts';
|
|
5
3
|
declare const _default: (options: SecurityConfig["nosniff"]) => MiddlewareFunc;
|
|
6
|
-
|
|
7
|
-
export { _default as default };
|
|
4
|
+
export default _default;
|
|
@@ -1,4 +1,28 @@
|
|
|
1
|
-
import "
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { checkIfIgnore } from "../utils.js";
|
|
2
|
+
// status codes for redirects
|
|
3
|
+
// @see https://github.com/jshttp/statuses/blob/master/index.js#L33
|
|
4
|
+
const RedirectStatus = {
|
|
5
|
+
300: true,
|
|
6
|
+
301: true,
|
|
7
|
+
302: true,
|
|
8
|
+
303: true,
|
|
9
|
+
305: true,
|
|
10
|
+
307: true,
|
|
11
|
+
308: true,
|
|
12
|
+
};
|
|
13
|
+
export default (options) => {
|
|
14
|
+
return async function nosniff(ctx, next) {
|
|
15
|
+
await next();
|
|
16
|
+
// ignore redirect response
|
|
17
|
+
if (RedirectStatus[ctx.status])
|
|
18
|
+
return;
|
|
19
|
+
const opts = {
|
|
20
|
+
...options,
|
|
21
|
+
...ctx.securityOptions.nosniff,
|
|
22
|
+
};
|
|
23
|
+
if (checkIfIgnore(opts, ctx))
|
|
24
|
+
return;
|
|
25
|
+
ctx.set('x-content-type-options', 'nosniff');
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9zbmlmZi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvbWlkZGxld2FyZXMvbm9zbmlmZi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQSxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRzVDLDZCQUE2QjtBQUM3QixtRUFBbUU7QUFDbkUsTUFBTSxjQUFjLEdBQTRCO0lBQzlDLEdBQUcsRUFBRSxJQUFJO0lBQ1QsR0FBRyxFQUFFLElBQUk7SUFDVCxHQUFHLEVBQUUsSUFBSTtJQUNULEdBQUcsRUFBRSxJQUFJO0lBQ1QsR0FBRyxFQUFFLElBQUk7SUFDVCxHQUFHLEVBQUUsSUFBSTtJQUNULEdBQUcsRUFBRSxJQUFJO0NBQ1YsQ0FBQztBQUVGLGVBQWUsQ0FBQyxPQUFrQyxFQUFrQixFQUFFO0lBQ3BFLE9BQU8sS0FBSyxVQUFVLE9BQU8sQ0FBQyxHQUFHLEVBQUUsSUFBSTtRQUNyQyxNQUFNLElBQUksRUFBRSxDQUFDO1FBRWIsMkJBQTJCO1FBQzNCLElBQUksY0FBYyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUM7WUFBRSxPQUFPO1FBRXZDLE1BQU0sSUFBSSxHQUFHO1lBQ1gsR0FBRyxPQUFPO1lBQ1YsR0FBRyxHQUFHLENBQUMsZUFBZSxDQUFDLE9BQU87U0FDL0IsQ0FBQztRQUNGLElBQUksYUFBYSxDQUFDLElBQUksRUFBRSxHQUFHLENBQUM7WUFBRSxPQUFPO1FBRXJDLEdBQUcsQ0FBQyxHQUFHLENBQUMsd0JBQXdCLEVBQUUsU0FBUyxDQUFDLENBQUM7SUFDL0MsQ0FBQyxDQUFDO0FBQ0osQ0FBQyxDQUFDIn0=
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
//#region src/lib/middlewares/referrerPolicy.d.ts
|
|
1
|
+
import type { MiddlewareFunc } from 'egg';
|
|
2
|
+
import type { SecurityConfig } from '../../config/config.default.ts';
|
|
5
3
|
declare const _default: (options: SecurityConfig["referrerPolicy"]) => MiddlewareFunc;
|
|
6
|
-
|
|
7
|
-
export { _default as default };
|
|
4
|
+
export default _default;
|
|
@@ -1,4 +1,35 @@
|
|
|
1
|
-
import "
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { checkIfIgnore } from "../utils.js";
|
|
2
|
+
// https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Referrer-Policy
|
|
3
|
+
const ALLOWED_POLICIES_ENUM = [
|
|
4
|
+
'no-referrer',
|
|
5
|
+
'no-referrer-when-downgrade',
|
|
6
|
+
'origin',
|
|
7
|
+
'origin-when-cross-origin',
|
|
8
|
+
'same-origin',
|
|
9
|
+
'strict-origin',
|
|
10
|
+
'strict-origin-when-cross-origin',
|
|
11
|
+
'unsafe-url',
|
|
12
|
+
'',
|
|
13
|
+
];
|
|
14
|
+
export default (options) => {
|
|
15
|
+
return async function referrerPolicy(ctx, next) {
|
|
16
|
+
await next();
|
|
17
|
+
const opts = {
|
|
18
|
+
...options,
|
|
19
|
+
// check refererPolicy for backward compatibility
|
|
20
|
+
// typo on the old version
|
|
21
|
+
// @see https://github.com/eggjs/security/blob/e3408408adec5f8d009d37f75126ed082481d0ac/lib/middlewares/referrerPolicy.js#L21C59-L21C72
|
|
22
|
+
// @ts-expect-error alias for referrerPolicy
|
|
23
|
+
...ctx.securityOptions.refererPolicy,
|
|
24
|
+
...ctx.securityOptions.referrerPolicy,
|
|
25
|
+
};
|
|
26
|
+
if (checkIfIgnore(opts, ctx))
|
|
27
|
+
return;
|
|
28
|
+
const policy = opts.value;
|
|
29
|
+
if (!ALLOWED_POLICIES_ENUM.includes(policy)) {
|
|
30
|
+
throw new Error(`"${policy}" is not available.`);
|
|
31
|
+
}
|
|
32
|
+
ctx.set('referrer-policy', policy);
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVmZXJyZXJQb2xpY3kuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL21pZGRsZXdhcmVzL3JlZmVycmVyUG9saWN5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFHNUMsNEVBQTRFO0FBQzVFLE1BQU0scUJBQXFCLEdBQUc7SUFDNUIsYUFBYTtJQUNiLDRCQUE0QjtJQUM1QixRQUFRO0lBQ1IsMEJBQTBCO0lBQzFCLGFBQWE7SUFDYixlQUFlO0lBQ2YsaUNBQWlDO0lBQ2pDLFlBQVk7SUFDWixFQUFFO0NBQ0gsQ0FBQztBQUVGLGVBQWUsQ0FBQyxPQUF5QyxFQUFrQixFQUFFO0lBQzNFLE9BQU8sS0FBSyxVQUFVLGNBQWMsQ0FBQyxHQUFHLEVBQUUsSUFBSTtRQUM1QyxNQUFNLElBQUksRUFBRSxDQUFDO1FBRWIsTUFBTSxJQUFJLEdBQUc7WUFDWCxHQUFHLE9BQU87WUFDVixpREFBaUQ7WUFDakQsMEJBQTBCO1lBQzFCLHVJQUF1STtZQUN2SSw0Q0FBNEM7WUFDNUMsR0FBRyxHQUFHLENBQUMsZUFBZSxDQUFDLGFBQWE7WUFDcEMsR0FBRyxHQUFHLENBQUMsZUFBZSxDQUFDLGNBQWM7U0FDdEMsQ0FBQztRQUNGLElBQUksYUFBYSxDQUFDLElBQUksRUFBRSxHQUFHLENBQUM7WUFBRSxPQUFPO1FBRXJDLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUM7UUFDMUIsSUFBSSxDQUFDLHFCQUFxQixDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1lBQzVDLE1BQU0sSUFBSSxLQUFLLENBQUMsSUFBSSxNQUFNLHFCQUFxQixDQUFDLENBQUM7UUFDbkQsQ0FBQztRQUVELEdBQUcsQ0FBQyxHQUFHLENBQUMsaUJBQWlCLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDckMsQ0FBQyxDQUFDO0FBQ0osQ0FBQyxDQUFDIn0=
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
//#region src/lib/middlewares/xframe.d.ts
|
|
1
|
+
import type { MiddlewareFunc } from 'egg';
|
|
2
|
+
import type { SecurityConfig } from '../../config/config.default.ts';
|
|
5
3
|
declare const _default: (options: SecurityConfig["xframe"]) => MiddlewareFunc;
|
|
6
|
-
|
|
7
|
-
export { _default as default };
|
|
4
|
+
export default _default;
|
|
@@ -1,4 +1,17 @@
|
|
|
1
|
-
import "
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { checkIfIgnore } from "../utils.js";
|
|
2
|
+
export default (options) => {
|
|
3
|
+
return async function xframe(ctx, next) {
|
|
4
|
+
await next();
|
|
5
|
+
const opts = {
|
|
6
|
+
...options,
|
|
7
|
+
...ctx.securityOptions.xframe,
|
|
8
|
+
};
|
|
9
|
+
if (checkIfIgnore(opts, ctx))
|
|
10
|
+
return;
|
|
11
|
+
// DENY, SAMEORIGIN, ALLOW-FROM
|
|
12
|
+
// https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options?redirectlocale=en-US&redirectslug=The_X-FRAME-OPTIONS_response_header
|
|
13
|
+
const value = opts.value || 'SAMEORIGIN';
|
|
14
|
+
ctx.set('x-frame-options', value);
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoieGZyYW1lLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xpYi9taWRkbGV3YXJlcy94ZnJhbWUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUc1QyxlQUFlLENBQUMsT0FBaUMsRUFBa0IsRUFBRTtJQUNuRSxPQUFPLEtBQUssVUFBVSxNQUFNLENBQUMsR0FBRyxFQUFFLElBQUk7UUFDcEMsTUFBTSxJQUFJLEVBQUUsQ0FBQztRQUViLE1BQU0sSUFBSSxHQUFHO1lBQ1gsR0FBRyxPQUFPO1lBQ1YsR0FBRyxHQUFHLENBQUMsZUFBZSxDQUFDLE1BQU07U0FDOUIsQ0FBQztRQUNGLElBQUksYUFBYSxDQUFDLElBQUksRUFBRSxHQUFHLENBQUM7WUFBRSxPQUFPO1FBRXJDLCtCQUErQjtRQUMvQixzSUFBc0k7UUFDdEksTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssSUFBSSxZQUFZLENBQUM7UUFDekMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUNwQyxDQUFDLENBQUM7QUFDSixDQUFDLENBQUMifQ==
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
//#region src/lib/middlewares/xssProtection.d.ts
|
|
1
|
+
import type { MiddlewareFunc } from 'egg';
|
|
2
|
+
import type { SecurityConfig } from '../../config/config.default.ts';
|
|
5
3
|
declare const _default: (options: SecurityConfig["xssProtection"]) => MiddlewareFunc;
|
|
6
|
-
|
|
7
|
-
export { _default as default };
|
|
4
|
+
export default _default;
|
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
import "
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { checkIfIgnore } from "../utils.js";
|
|
2
|
+
export default (options) => {
|
|
3
|
+
return async function xssProtection(ctx, next) {
|
|
4
|
+
await next();
|
|
5
|
+
const opts = {
|
|
6
|
+
...options,
|
|
7
|
+
...ctx.securityOptions.xssProtection,
|
|
8
|
+
};
|
|
9
|
+
if (checkIfIgnore(opts, ctx))
|
|
10
|
+
return;
|
|
11
|
+
ctx.set('x-xss-protection', opts.value);
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoieHNzUHJvdGVjdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvbWlkZGxld2FyZXMveHNzUHJvdGVjdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQSxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRzVDLGVBQWUsQ0FBQyxPQUF3QyxFQUFrQixFQUFFO0lBQzFFLE9BQU8sS0FBSyxVQUFVLGFBQWEsQ0FBQyxHQUFHLEVBQUUsSUFBSTtRQUMzQyxNQUFNLElBQUksRUFBRSxDQUFDO1FBRWIsTUFBTSxJQUFJLEdBQUc7WUFDWCxHQUFHLE9BQU87WUFDVixHQUFHLEdBQUcsQ0FBQyxlQUFlLENBQUMsYUFBYTtTQUNyQyxDQUFDO1FBQ0YsSUFBSSxhQUFhLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQztZQUFFLE9BQU87UUFFckMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDMUMsQ0FBQyxDQUFDO0FBQ0osQ0FBQyxDQUFDIn0=
|
package/dist/lib/utils.d.ts
CHANGED
|
@@ -1,24 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
//#region src/lib/utils.d.ts
|
|
6
|
-
|
|
1
|
+
import type { Context } from 'egg';
|
|
2
|
+
import type { PathMatchingFun } from 'egg-path-matching';
|
|
3
|
+
import type { SecurityConfig } from '../config/config.default.ts';
|
|
7
4
|
/**
|
|
8
5
|
* Check whether a domain is in the safe domain white list or not.
|
|
9
6
|
* @param {String} domain The inputted domain.
|
|
10
7
|
* @param {Array<string>} whiteList The white list for domain.
|
|
11
8
|
* @return {Boolean} If the `domain` is in the white list, return true; otherwise false.
|
|
12
9
|
*/
|
|
13
|
-
declare function isSafeDomain(domain: string, whiteList: string[]): boolean;
|
|
14
|
-
declare function isSafePath(path: string, ctx: Context): boolean;
|
|
15
|
-
declare function checkIfIgnore(opts: {
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
export declare function isSafeDomain(domain: string, whiteList: string[]): boolean;
|
|
11
|
+
export declare function isSafePath(path: string, ctx: Context): boolean;
|
|
12
|
+
export declare function checkIfIgnore(opts: {
|
|
13
|
+
enable: boolean;
|
|
14
|
+
matching?: PathMatchingFun;
|
|
18
15
|
}, ctx: Context): boolean;
|
|
19
|
-
declare function getCookieDomain(hostname: string): string;
|
|
20
|
-
declare function merge(origin: Record<string, any>, opts?: Record<string, any>): Record<string, any>;
|
|
21
|
-
declare function preprocessConfig(config: SecurityConfig): void;
|
|
22
|
-
declare function getFromUrl(url: string, prop: string): string | null;
|
|
23
|
-
//#endregion
|
|
24
|
-
export { checkIfIgnore, getCookieDomain, getFromUrl, isSafeDomain, isSafePath, merge, preprocessConfig };
|
|
16
|
+
export declare function getCookieDomain(hostname: string): string;
|
|
17
|
+
export declare function merge(origin: Record<string, any>, opts?: Record<string, any>): Record<string, any>;
|
|
18
|
+
export declare function preprocessConfig(config: SecurityConfig): void;
|
|
19
|
+
export declare function getFromUrl(url: string, prop: string): string | null;
|
package/dist/lib/utils.js
CHANGED
|
@@ -1,3 +1,192 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { normalize } from 'node:path';
|
|
2
|
+
import matcher from 'matcher';
|
|
3
|
+
import IP from '@eggjs/ip';
|
|
4
|
+
/**
|
|
5
|
+
* Check whether a domain is in the safe domain white list or not.
|
|
6
|
+
* @param {String} domain The inputted domain.
|
|
7
|
+
* @param {Array<string>} whiteList The white list for domain.
|
|
8
|
+
* @return {Boolean} If the `domain` is in the white list, return true; otherwise false.
|
|
9
|
+
*/
|
|
10
|
+
export function isSafeDomain(domain, whiteList) {
|
|
11
|
+
// domain must be string, otherwise return false
|
|
12
|
+
if (typeof domain !== 'string')
|
|
13
|
+
return false;
|
|
14
|
+
// Ignore case sensitive first
|
|
15
|
+
domain = domain.toLowerCase();
|
|
16
|
+
// add prefix `.`, because all domains in white list start with `.`
|
|
17
|
+
const hostname = '.' + domain;
|
|
18
|
+
return whiteList.some(rule => {
|
|
19
|
+
// Check whether we've got '*' as a wild character symbol
|
|
20
|
+
if (rule.includes('*')) {
|
|
21
|
+
return matcher.isMatch(domain, rule);
|
|
22
|
+
}
|
|
23
|
+
// If domain is an absolute path such as `http://...`
|
|
24
|
+
// We can directly check whether it directly equals to `domain`
|
|
25
|
+
// And we don't need to cope with `endWith`.
|
|
26
|
+
if (domain === rule)
|
|
27
|
+
return true;
|
|
28
|
+
// ensure wwweggjs.com not match eggjs.com
|
|
29
|
+
if (!rule.startsWith('.'))
|
|
30
|
+
rule = `.${rule}`;
|
|
31
|
+
return hostname.endsWith(rule);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
export function isSafePath(path, ctx) {
|
|
35
|
+
path = '.' + path;
|
|
36
|
+
if (path.includes('%')) {
|
|
37
|
+
try {
|
|
38
|
+
path = decodeURIComponent(path);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
if (ctx.app.config.env === 'local' || ctx.app.config.env === 'unittest') {
|
|
42
|
+
// not under production environment, output log
|
|
43
|
+
ctx.coreLogger.warn('[@eggjs/security: dta global block] : decode file path %j failed.', path);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const normalizePath = normalize(path);
|
|
48
|
+
return !(normalizePath.startsWith('../') || normalizePath.startsWith('..\\'));
|
|
49
|
+
}
|
|
50
|
+
export function checkIfIgnore(opts, ctx) {
|
|
51
|
+
// check opts.enable first
|
|
52
|
+
if (!opts.enable)
|
|
53
|
+
return true;
|
|
54
|
+
return !opts.matching?.(ctx);
|
|
55
|
+
}
|
|
56
|
+
const IP_RE = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
|
|
57
|
+
const topDomains = {};
|
|
58
|
+
['.net.cn', '.gov.cn', '.org.cn', '.com.cn'].forEach(item => {
|
|
59
|
+
topDomains[item] = 2 - item.split('.').length;
|
|
60
|
+
});
|
|
61
|
+
export function getCookieDomain(hostname) {
|
|
62
|
+
// TODO(fengmk2): support ipv6
|
|
63
|
+
if (IP_RE.test(hostname)) {
|
|
64
|
+
return hostname;
|
|
65
|
+
}
|
|
66
|
+
// app.test.domain.com => .test.domain.com
|
|
67
|
+
// app.stable.domain.com => .domain.com
|
|
68
|
+
// app.domain.com => .domain.com
|
|
69
|
+
// domain=.domain.com;
|
|
70
|
+
const splits = hostname.split('.');
|
|
71
|
+
let index = -2;
|
|
72
|
+
// only when `*.test.*.com` set `.test.*.com`
|
|
73
|
+
if (splits.length >= 4 && splits[splits.length - 3] === 'test') {
|
|
74
|
+
index = -3;
|
|
75
|
+
}
|
|
76
|
+
let domain = getDomain(splits, index);
|
|
77
|
+
if (topDomains[domain]) {
|
|
78
|
+
// app.foo.org.cn => .foo.org.cn
|
|
79
|
+
domain = getDomain(splits, index + topDomains[domain]);
|
|
80
|
+
}
|
|
81
|
+
return domain;
|
|
82
|
+
}
|
|
83
|
+
function getDomain(splits, index) {
|
|
84
|
+
return '.' + splits.slice(index).join('.');
|
|
85
|
+
}
|
|
86
|
+
export function merge(origin, opts) {
|
|
87
|
+
if (!opts) {
|
|
88
|
+
return origin;
|
|
89
|
+
}
|
|
90
|
+
const res = {};
|
|
91
|
+
const originKeys = Object.keys(origin);
|
|
92
|
+
for (let i = 0; i < originKeys.length; i++) {
|
|
93
|
+
const key = originKeys[i];
|
|
94
|
+
res[key] = origin[key];
|
|
95
|
+
}
|
|
96
|
+
const keys = Object.keys(opts);
|
|
97
|
+
for (let i = 0; i < keys.length; i++) {
|
|
98
|
+
const key = keys[i];
|
|
99
|
+
res[key] = opts[key];
|
|
100
|
+
}
|
|
101
|
+
return res;
|
|
102
|
+
}
|
|
103
|
+
export function preprocessConfig(config) {
|
|
104
|
+
// transfer ssrf.ipBlackList to ssrf.checkAddress
|
|
105
|
+
// ssrf.ipExceptionList can easily pick out unwanted ips from ipBlackList
|
|
106
|
+
// checkAddress has higher priority than ipBlackList
|
|
107
|
+
const ssrf = config.ssrf;
|
|
108
|
+
if (ssrf && ssrf.ipBlackList && !ssrf.checkAddress) {
|
|
109
|
+
const blackList = ssrf.ipBlackList.map(getContains);
|
|
110
|
+
const exceptionList = (ssrf.ipExceptionList || []).map(getContains);
|
|
111
|
+
const hostnameExceptionList = ssrf.hostnameExceptionList;
|
|
112
|
+
ssrf.checkAddress = (ipAddresses, _family, hostname) => {
|
|
113
|
+
// Check white hostname first
|
|
114
|
+
if (hostname && hostnameExceptionList) {
|
|
115
|
+
if (hostnameExceptionList.includes(hostname)) {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// ipAddresses will be array address on Node.js >= 20
|
|
120
|
+
// [
|
|
121
|
+
// { address: '220.181.125.241', family: 4 },
|
|
122
|
+
// { address: '240e:964:ea02:b00:3::3ec', family: 6 }
|
|
123
|
+
// ]
|
|
124
|
+
if (!Array.isArray(ipAddresses)) {
|
|
125
|
+
ipAddresses = [ipAddresses];
|
|
126
|
+
}
|
|
127
|
+
for (const ipAddress of ipAddresses) {
|
|
128
|
+
let address;
|
|
129
|
+
if (typeof ipAddress === 'string') {
|
|
130
|
+
address = ipAddress;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
// FIXME: should support ipv6
|
|
134
|
+
if (ipAddress.family === 6) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
address = ipAddress.address;
|
|
138
|
+
}
|
|
139
|
+
// check white list first
|
|
140
|
+
for (const exception of exceptionList) {
|
|
141
|
+
if (exception(address)) {
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// check black list
|
|
146
|
+
for (const contains of blackList) {
|
|
147
|
+
if (contains(address)) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// default allow
|
|
153
|
+
return true;
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
// Make sure that `whiteList` or `protocolWhiteList` is case insensitive
|
|
157
|
+
config.domainWhiteList = config.domainWhiteList || [];
|
|
158
|
+
config.domainWhiteList = config.domainWhiteList.map((domain) => domain.toLowerCase());
|
|
159
|
+
config.protocolWhiteList = config.protocolWhiteList || [];
|
|
160
|
+
config.protocolWhiteList = config.protocolWhiteList.map((protocol) => protocol.toLowerCase());
|
|
161
|
+
// Make sure refererWhiteList is case insensitive
|
|
162
|
+
if (config.csrf && config.csrf.refererWhiteList) {
|
|
163
|
+
config.csrf.refererWhiteList = config.csrf.refererWhiteList.map((ref) => ref.toLowerCase());
|
|
164
|
+
}
|
|
165
|
+
// Directly converted to Set collection by a private property (not documented),
|
|
166
|
+
// And we NO LONGER need to do conversion in `foreach` again and again in `lib/helper/surl.ts`.
|
|
167
|
+
const protocolWhiteListSet = new Set(config.protocolWhiteList);
|
|
168
|
+
protocolWhiteListSet.add('http');
|
|
169
|
+
protocolWhiteListSet.add('https');
|
|
170
|
+
protocolWhiteListSet.add('file');
|
|
171
|
+
protocolWhiteListSet.add('data');
|
|
172
|
+
Object.defineProperty(config, '__protocolWhiteListSet', {
|
|
173
|
+
value: protocolWhiteListSet,
|
|
174
|
+
enumerable: false,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
export function getFromUrl(url, prop) {
|
|
178
|
+
try {
|
|
179
|
+
const parsed = new URL(url);
|
|
180
|
+
return Reflect.get(parsed, prop);
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function getContains(ip) {
|
|
187
|
+
if (IP.isV4Format(ip) || IP.isV6Format(ip)) {
|
|
188
|
+
return (address) => address === ip;
|
|
189
|
+
}
|
|
190
|
+
return IP.cidrSubnet(ip).contains;
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbGliL3V0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFFdEMsT0FBTyxPQUFPLE1BQU0sU0FBUyxDQUFDO0FBQzlCLE9BQU8sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQU0zQjs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxZQUFZLENBQUMsTUFBYyxFQUFFLFNBQW1CO0lBQzlELGdEQUFnRDtJQUNoRCxJQUFJLE9BQU8sTUFBTSxLQUFLLFFBQVE7UUFBRSxPQUFPLEtBQUssQ0FBQztJQUM3Qyw4QkFBOEI7SUFDOUIsTUFBTSxHQUFHLE1BQU0sQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUM5QixtRUFBbUU7SUFDbkUsTUFBTSxRQUFRLEdBQUcsR0FBRyxHQUFHLE1BQU0sQ0FBQztJQUU5QixPQUFPLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUU7UUFDM0IseURBQXlEO1FBQ3pELElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3ZCLE9BQU8sT0FBTyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDdkMsQ0FBQztRQUNELHFEQUFxRDtRQUNyRCwrREFBK0Q7UUFDL0QsNENBQTRDO1FBQzVDLElBQUksTUFBTSxLQUFLLElBQUk7WUFBRSxPQUFPLElBQUksQ0FBQztRQUNqQywwQ0FBMEM7UUFDMUMsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDO1lBQUUsSUFBSSxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7UUFDN0MsT0FBTyxRQUFRLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2pDLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVELE1BQU0sVUFBVSxVQUFVLENBQUMsSUFBWSxF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
|
package/dist/types.d.ts
CHANGED
|
@@ -1,3 +1,36 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
1
|
+
import type { SecurityConfig, SecurityHelperConfig } from './config/config.default.ts';
|
|
2
|
+
import type { HttpClientRequestURL, HttpClientResponse, HttpClientOptions } from './lib/extend/safe_curl.ts';
|
|
3
|
+
declare module 'egg' {
|
|
4
|
+
interface EggAppConfig {
|
|
5
|
+
/**
|
|
6
|
+
* security options
|
|
7
|
+
* @member Config#security
|
|
8
|
+
*/
|
|
9
|
+
security: SecurityConfig;
|
|
10
|
+
helper: SecurityHelperConfig;
|
|
11
|
+
}
|
|
12
|
+
interface Agent {
|
|
13
|
+
safeCurl<T = any>(url: HttpClientRequestURL, options?: HttpClientOptions): Promise<HttpClientResponse<T>>;
|
|
14
|
+
}
|
|
15
|
+
interface Application {
|
|
16
|
+
injectCsrf(html: string): string;
|
|
17
|
+
injectNonce(html: string): string;
|
|
18
|
+
injectHijackingDefense(html: string): string;
|
|
19
|
+
safeCurl<T = any>(url: HttpClientRequestURL, options?: HttpClientOptions): Promise<HttpClientResponse<T>>;
|
|
20
|
+
}
|
|
21
|
+
interface Context {
|
|
22
|
+
get securityOptions(): Partial<SecurityConfig & SecurityHelperConfig>;
|
|
23
|
+
isSafeDomain(domain: string, customWhiteList?: string[]): boolean;
|
|
24
|
+
get nonce(): string;
|
|
25
|
+
get csrf(): string;
|
|
26
|
+
ensureCsrfSecret(rotate?: boolean): void;
|
|
27
|
+
rotateCsrfSecret(): void;
|
|
28
|
+
assertCsrf(): void;
|
|
29
|
+
safeCurl<T = any>(url: HttpClientRequestURL, options?: HttpClientOptions): Promise<HttpClientResponse<T>>;
|
|
30
|
+
unsafeRedirect(url: string, alt?: string): void;
|
|
31
|
+
}
|
|
32
|
+
interface Response {
|
|
33
|
+
unsafeRedirect(url: string, alt?: string): void;
|
|
34
|
+
redirect(url: string, alt?: string): void;
|
|
35
|
+
}
|
|
36
|
+
}
|
package/dist/types.js
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export { };
|
|
1
|
+
export {};
|
|
2
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiJ9
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eggjs/security",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.21",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"zod": "^3.24.1"
|
|
85
85
|
},
|
|
86
86
|
"peerDependencies": {
|
|
87
|
-
"egg": "4.1.0-beta.
|
|
87
|
+
"egg": "4.1.0-beta.21"
|
|
88
88
|
},
|
|
89
89
|
"devDependencies": {
|
|
90
90
|
"@types/escape-html": "^1.0.4",
|
|
@@ -100,9 +100,9 @@
|
|
|
100
100
|
"tsdown": "^0.15.4",
|
|
101
101
|
"typescript": "^5.9.3",
|
|
102
102
|
"vitest": "4.0.0-beta.16",
|
|
103
|
-
"@eggjs/mock": "7.0.0-beta.
|
|
104
|
-
"@eggjs/tsconfig": "3.1.0-beta.
|
|
105
|
-
"@eggjs/supertest": "9.0.0-beta.
|
|
103
|
+
"@eggjs/mock": "7.0.0-beta.21",
|
|
104
|
+
"@eggjs/tsconfig": "3.1.0-beta.21",
|
|
105
|
+
"@eggjs/supertest": "9.0.0-beta.21"
|
|
106
106
|
},
|
|
107
107
|
"files": [
|
|
108
108
|
"dist"
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
"module": "./dist/index.js",
|
|
112
112
|
"types": "./dist/index.d.ts",
|
|
113
113
|
"scripts": {
|
|
114
|
-
"build": "tsdown",
|
|
114
|
+
"build": "tsdown && rimraf dist && tsc -b --clean && tsc",
|
|
115
115
|
"typecheck": "tsc --noEmit",
|
|
116
116
|
"lint": "oxlint --type-aware",
|
|
117
117
|
"lint:fix": "npm run lint -- --fix",
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { safeCurlForApplication } from "./safe_curl-UlViaxoF.js";
|
|
2
|
-
import { Application } from "egg";
|
|
3
|
-
|
|
4
|
-
//#region src/app/extend/application.ts
|
|
5
|
-
const INPUT_CSRF = "\r\n<input type=\"hidden\" name=\"_csrf\" value=\"{{ctx.csrf}}\" /></form>";
|
|
6
|
-
const INJECTION_DEFENSE = "<!--for injection--><!--</html>--><!--for injection-->";
|
|
7
|
-
var SecurityApplication = class extends Application {
|
|
8
|
-
injectCsrf(html) {
|
|
9
|
-
html = html.replace(/(<form.*?>)([\s\S]*?)<\/form>/gi, (_, $1, $2) => {
|
|
10
|
-
const match = $2;
|
|
11
|
-
if (match.indexOf("name=\"_csrf\"") !== -1 || match.indexOf("name='_csrf'") !== -1) return $1 + match + "</form>";
|
|
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=")) $1 += " nonce=\"{{ctx.nonce}}\"";
|
|
19
|
-
return "<script" + $1 + ">" + $2 + "<\/script>";
|
|
20
|
-
});
|
|
21
|
-
return html;
|
|
22
|
-
}
|
|
23
|
-
injectHijackingDefense(html) {
|
|
24
|
-
return INJECTION_DEFENSE + html + INJECTION_DEFENSE;
|
|
25
|
-
}
|
|
26
|
-
async safeCurl(url, options) {
|
|
27
|
-
return await safeCurlForApplication(this, url, options);
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
//#endregion
|
|
32
|
-
export { SecurityApplication };
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { HttpClientOptions, HttpClientRequestURL, HttpClientResponse } from "./safe_curl-mqZZv_YQ.js";
|
|
2
|
-
import { Application } from "egg";
|
|
3
|
-
|
|
4
|
-
//#region src/app/extend/application.d.ts
|
|
5
|
-
declare class SecurityApplication extends Application {
|
|
6
|
-
injectCsrf(html: string): string;
|
|
7
|
-
injectNonce(html: string): string;
|
|
8
|
-
injectHijackingDefense(html: string): string;
|
|
9
|
-
safeCurl<T = any>(url: HttpClientRequestURL, options?: HttpClientOptions): Promise<HttpClientResponse<T>>;
|
|
10
|
-
}
|
|
11
|
-
//#endregion
|
|
12
|
-
export { SecurityApplication };
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
//#region src/lib/helper/cliFilter.ts
|
|
2
|
-
/**
|
|
3
|
-
* remote command execution
|
|
4
|
-
*/
|
|
5
|
-
const BASIC_ALPHABETS = new Set("abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ.-_".split(""));
|
|
6
|
-
function cliFilter(text) {
|
|
7
|
-
const str = "" + text;
|
|
8
|
-
let res = "";
|
|
9
|
-
let ascii;
|
|
10
|
-
for (let index = 0; index < str.length; index++) {
|
|
11
|
-
ascii = str[index];
|
|
12
|
-
if (BASIC_ALPHABETS.has(ascii)) res += ascii;
|
|
13
|
-
}
|
|
14
|
-
return res;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
//#endregion
|
|
18
|
-
export { cliFilter };
|