入侵检测系统实战:从原理到部署的完整技术指南
先看效果,再看代码
上周我们线上一个内部管理后台突然被刷了大量异常请求,虽然没造成数据泄露,但日志里全是 403 和 500,差点把服务器打崩。事后复盘发现,前端其实能做点事——不是防攻击,而是快速感知异常行为,第一时间上报,让后端或运维介入。这就是我今天要聊的:前端怎么搞一套轻量级的“入侵检测”机制。
别想太复杂,不是装个防火墙那种。我们干的是:监听用户行为里的“不对劲”,比如短时间内疯狂点击、高频提交表单、或者试图绕过前端校验直接发奇怪 payload。亲测有效,成本低,适合中小项目。
核心代码就这几行
最简单的做法:记录用户操作频率,超过阈值就上报。比如登录页,正常人不会 1 秒点 5 次登录按钮。我直接上代码:
// 全局防刷计数器(按操作类型)
const actionCount = new Map();
const THRESHOLD = 5; // 10秒内最多5次
const WINDOW_MS = 10000;
function trackAction(actionName) {
const now = Date.now();
const records = actionCount.get(actionName) || [];
// 清掉过期记录
const validRecords = records.filter(time => now - time < WINDOW_MS);
validRecords.push(now);
if (validReserved.length >= THRESHOLD) {
// 触发告警!
reportSuspiciousActivity(actionName, validRecords.length);
// 可选:临时禁用该操作
disableActionTemporarily(actionName);
}
actionCount.set(actionName, validRecords);
}
function reportSuspiciousActivity(action, count) {
fetch('https://jztheme.com/api/security-alert', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action,
count,
userAgent: navigator.userAgent,
timestamp: Date.now()
})
}).catch(() => {}); // 失败也不影响主流程
}
用的时候很简单,在关键按钮点击处加一行:
document.getElementById('loginBtn').addEventListener('click', () => {
trackAction('login_attempt');
// ...原有登录逻辑
});
这个方案我在线上跑了两个月,抓到好几波脚本刷登录,准确率还行。注意:别用 localStorage 存计数,容易被清;Map 在内存里,刷新就没了,但对“实时高频”检测够用。
这个场景最好用
除了按钮点击,还有几个地方特别适合加这种检测:
- 表单提交:尤其是带 token 的敏感操作,比如修改密码、转账。如果用户在 30 秒内提交了 10 次不同密码,大概率是暴力破解。
- API 调用失败重试:正常用户重试 2-3 次就放弃了,如果某个接口连续失败 10 次还在发,可能是工具在跑。
- 路由跳转异常:比如用户反复访问 /admin 页面但没权限,可以记录下这种“试探”行为。
举个表单的例子,结合前端校验一起用:
function handleSubmit(formData) {
// 先做基础校验
if (!validateForm(formData)) {
trackAction('invalid_form_submit'); // 记录无效提交
return;
}
// 正常提交
fetch('/api/update-profile', { method: 'POST', body: formData })
.catch(err => {
// 提交失败也记录
trackAction('form_submit_failure');
});
}
这样后端就能看到:哪些用户总在提交非法数据,是不是在探测字段规则。
踩坑提醒:这三点一定注意
我折腾这个功能时踩了几个坑,分享出来帮你避雷:
- 别阻塞主流程:检测和上报必须异步,不能因为安全逻辑卡住用户操作。上面代码里用了
fetch().catch()就是这个原因。有一次我忘了 catch,网络慢时整个页面卡死,用户骂疯了。 - 阈值别设太死:THRESHOLD 设成 5 是经验值,但不同场景要调。比如搜索框可能用户真会快速删改,这时候阈值得放宽到 10+。建议先灰度观察几天日志再定。
- 别信前端数据:所有上报的数据,后端必须二次校验。前端能被绕过,比如有人直接调
trackAction('login_attempt')刷日志。所以 API 要加签名或 token,别裸奔。
还有个小细节:内存泄漏。Map 里的记录如果不清理,长期不刷新的页面(比如后台系统)会越积越多。我后来加了个定时清理:
setInterval(() => {
const now = Date.now();
for (const [action, records] of actionCount.entries()) {
const valid = records.filter(t => now - t < WINDOW_MS);
if (valid.length === 0) {
actionCount.delete(action); // 清空无用记录
} else {
actionCount.set(action, valid);
}
}
}, 60000); // 每分钟清理一次
高级技巧:结合行为分析
如果项目重要,可以玩点更细的。比如记录鼠标移动轨迹、键盘输入节奏——正常人和机器行为差异很大。不过这招成本高,我只在金融类项目里用过。
简单版:检测“非人类操作”。比如用户从打开页面到提交表单只用了 800ms,但表单有 5 个字段,人类不可能这么快。代码示意:
let pageOpenTime = Date.now();
document.getElementById('submitBtn').addEventListener('click', () => {
const timeSpent = Date.now() - pageOpenTime;
if (timeSpent < 1000) { // 1秒内提交
reportSuspiciousActivity('too_fast_submission');
}
// ...其他逻辑
});
更狠一点,可以算输入速度。比如密码框,如果每秒输入 20 个字符,基本是粘贴或脚本。但要注意移动端软键盘可能影响判断,别误伤。
这类方案我没全量上,只在关键路径加了。毕竟性能有损耗,而且隐私问题要小心——别记录具体输入内容,只记时间和次数。
最后说两句
前端做入侵检测,本质是“辅助监控”,不是替代后端安全。但它能让你在问题扩大前收到预警,比等日志报警快得多。我这套方案上线后,配合后端的 IP 封禁,暴力破解尝试少了 70%。
以上是我踩坑后的总结,希望对你有帮助。这个技术的拓展用法还有很多,比如结合 CSP 报告、检测 DOM 篡改,后续会继续分享这类博客。有更优的实现方式欢迎评论区交流——特别是怎么平衡性能和检测粒度,我现在还在优化。

暂无评论