fix(server): 修复 IP 封锁绕过漏洞并补充审计日志
- 支持 TRUST_PROXY 配置,由 express 正确解析客户端 IP,防止伪造 X-Forwarded-For - 修复 IP 封锁使用对象作为 Map key 导致失效的问题,改用字符串 IP - 主密码解锁失败时记录 IP 失败次数,达到阈值后封锁 - 补充条目更新操作的审计日志
这个提交包含在:
+33
@@ -0,0 +1,33 @@
|
||||
'use strict';
|
||||
// 验证 IP 封锁逻辑修复:必须用字符串 IP 作 key,而非对象
|
||||
const ipFails = new Map();
|
||||
const IP_WINDOW = 30 * 60 * 1000, IP_MAX_FAIL = 5;
|
||||
function recordIpFail(ip) {
|
||||
const now = Date.now();
|
||||
let r = ipFails.get(ip);
|
||||
if (!r || now - r.first > IP_WINDOW) r = { count: 0, first: now };
|
||||
r.count++; ipFails.set(ip, r);
|
||||
return r.count >= IP_MAX_FAIL;
|
||||
}
|
||||
function isIpBlocked(ip) {
|
||||
const r = ipFails.get(ip);
|
||||
if (!r) return false;
|
||||
if (Date.now() - r.first > IP_WINDOW) { ipFails.delete(ip); return false; }
|
||||
return r.count >= IP_MAX_FAIL;
|
||||
}
|
||||
|
||||
// 旧 bug:传入对象 {ip:'1.2.3.4'} 作 key
|
||||
const ipObj = { ip: '1.2.3.4' };
|
||||
let blockedOld = false;
|
||||
for (let i = 0; i < 5; i++) recordIpFail(ipObj);
|
||||
blockedOld = isIpBlocked(ipObj); // 每次都是新对象 -> 永远 false
|
||||
|
||||
// 修复后:传入字符串 '1.2.3.4'
|
||||
const ipStr = '1.2.3.4';
|
||||
let blockedNew = false;
|
||||
for (let i = 0; i < 5; i++) recordIpFail(ipStr);
|
||||
blockedNew = isIpBlocked(ipStr);
|
||||
|
||||
console.log('修复前(对象key)是否封锁:', blockedOld, '-> 期望 false(bug 表现)');
|
||||
console.log('修复后(字符串key)是否封锁:', blockedNew, '-> 期望 true');
|
||||
process.exit(blockedNew === true ? 0 : 1);
|
||||
在新工单中引用
屏蔽一个用户