index.js
3.77 KB
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
'use strict';
const _ = require('lodash');
const logger = global.yoho.logger;
const ip = require('./rules/ip-list');
const userAgent = require('./rules/useragent');
const ipWhiteList = require('./rules/ip-white-list');
const qpsLimiter = require('./rules/qps-limit');
const co = Promise.coroutine;
// const asynchronous = require('./rules/asynchronous');
// const fakerLimiter = require('./rules/faker-limit');
const captchaPolicy = require('./policies/captcha');
// const reporterPolicy = require('./policies/reporter');
const IP_WHITE_LIST = [
'106.38.38.146', // 北京办公区域
'106.38.38.147', // 北京办公区域
'106.39.86.227', // 北京办公区域
'218.94.75.58', // 南京办公区域
'218.94.75.50', // 南京办公区域
'218.94.77.166', // 南京办公区域
// '222.73.196.18', // B站合作方单击次数快加白名单
'123.206.73.107', // 腾讯云出口IP
'139.199.35.21', // 腾讯云出口IP
'139.199.29.44', // 腾讯云出口IP
'123.206.21.19' // 腾讯云出口IP
];
const IP_WHITE_SEGMENT = [
'10.66.', // 内网IP段
'192.168.' // 内网IP段
];
const PATH_WHITE_LIST = [
'/3party/check',
'/passport/images.png',
'/passport/cert/headerTip',
'/common/getbanner',
'/common/suggestfeedback',
'/product/search/history',
'/product/search/suggest'
];
const limiter = (rule, policy, context) => {
return rule(context, policy);
};
// 排除条件:ip白名单/路径白名单/异步请求/登录用户
const _excluded = (req) => {
let remoteIp = req.yoho.clientIp || '';
let remoteIpSegment = `${remoteIp.split('.').slice(0, 2).join('.')}.`;
return co(function* () {
let atWhiteList = yield ipWhiteList(remoteIp);
return Boolean(
atWhiteList ||
_.includes(IP_WHITE_LIST, remoteIp) ||
_.includes(IP_WHITE_SEGMENT, remoteIpSegment) ||
_.includes(PATH_WHITE_LIST, req.path) ||
req.xhr ||
!_.isEmpty(_.get(req, 'user.uid'))
);
})();
};
module.exports = (req, res, next) => {
const remoteIp = req.yoho.clientIp || '';
const enabled = !_.get(req.app.locals, 'pc.sys.noLimiter');
// 开关为关或者未获取到remoteIp,放行
if (!enabled || !remoteIp) {
logger.debug(`request remote ip: ${remoteIp}; enabled: ${enabled}`);
return next();
}
return co(function* () {
let excluded = yield _excluded(req);
logger.debug(`request remote ip: ${remoteIp}; excluded: ${excluded}; enabled: ${enabled}`);
// 白名单,放行
if (excluded) {
return next();
}
const context = {
req: req,
res: res,
next: next,
remoteIp: remoteIp
};
let results = yield Promise.all([
limiter(userAgent, captchaPolicy, context),
limiter(ip, captchaPolicy, context),
limiter(qpsLimiter, captchaPolicy, context)
// limiter(asynchronous, captchaPolicy, context)
// limiter(fakerLimiter, reporterPolicy, context)
]);
let allPass = true, exclusion = false, policy = null;
logger.debug('limiter result: ' + JSON.stringify(results));
_.forEach(results, (result) => {
if (typeof result === 'object' && !exclusion) {
exclusion = result.exclusion;
}
if (typeof result === 'function') {
allPass = false;
policy = result;
}
});
if (exclusion) {
return next();
} else if (!allPass && policy) {
policy(req, res, next);
} else {
return next();
}
})().catch((err) => {
logger.error(err);
return next();
});
};