-
Notifications
You must be signed in to change notification settings - Fork 568
/
helper.ts
103 lines (90 loc) 路 2.49 KB
/
helper.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import { IMiddleware, Middleware, MidwayFrameworkType } from '@midwayjs/core';
import * as escape from 'escape-html';
import { filterXSS } from 'xss';
@Middleware()
export class SecurityHelper implements IMiddleware<any, any> {
resolve(app) {
if (app.getFrameworkType() === MidwayFrameworkType.WEB_EXPRESS) {
return async (req: any, res, next) => {
return this.compatibleMiddleware(req, req, res, next);
};
} else {
return async (ctx, next) => {
return this.compatibleMiddleware(ctx, ctx.request, ctx, next);
};
}
}
async compatibleMiddleware(context, req, res, next) {
context.security = {
escape,
html: (htmlCode: string) => filterXSS(htmlCode),
js: safeJS,
json: safeJSON,
};
return next();
}
}
const MATCH_VULNERABLE_REGEXP = /[\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]/;
const BASIC_ALPHABETS = new Set(
'abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('')
);
const map = {
'\t': '\\t',
'\n': '\\n',
'\r': '\\r',
};
const safeJS = (jsCode: string): string => {
jsCode = `${jsCode || ''}`;
const match = MATCH_VULNERABLE_REGEXP.exec(jsCode);
if (!match) {
return jsCode;
}
let res = '';
let index = 0;
let lastIndex = 0;
let ascii;
for (index = match.index; index < jsCode.length; index++) {
ascii = jsCode[index];
if (BASIC_ALPHABETS.has(ascii)) {
continue;
} else {
if (map[ascii] === undefined) {
const code = ascii.charCodeAt(0);
if (code > 127) {
continue;
} else {
map[ascii] = '\\x' + code.toString(16);
}
}
}
if (lastIndex !== index) {
res += jsCode.substring(lastIndex, index);
}
lastIndex = index + 1;
res += map[ascii];
}
return lastIndex !== index ? res + jsCode.substring(lastIndex, index) : res;
};
function sanitizeKey(obj) {
if (typeof obj !== 'object') return obj;
if (Array.isArray(obj)) return obj;
if (obj === null) return null;
if (obj instanceof Boolean) return obj;
if (obj instanceof Number) return obj;
if (obj instanceof Buffer) return obj.toString();
for (const k in obj) {
const escapedK = safeJS(k);
if (escapedK !== k) {
obj[escapedK] = sanitizeKey(obj[k]);
obj[k] = undefined;
} else {
obj[k] = sanitizeKey(obj[k]);
}
}
return obj;
}
const safeJSON = (object: any): string => {
return JSON.stringify(sanitizeKey(object), (k, v) => {
return typeof v === 'string' ? safeJS(v) : v;
});
};