入侵检测系统实战:从原理到部署的完整技术指南

东方士娇 安全 阅读 605
赞 26 收藏
二维码
手机扫码查看
反馈

先看效果,再看代码

上周我们线上一个内部管理后台突然被刷了大量异常请求,虽然没造成数据泄露,但日志里全是 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');
    });
}

这样后端就能看到:哪些用户总在提交非法数据,是不是在探测字段规则。

踩坑提醒:这三点一定注意

我折腾这个功能时踩了几个坑,分享出来帮你避雷:

  1. 别阻塞主流程:检测和上报必须异步,不能因为安全逻辑卡住用户操作。上面代码里用了 fetch().catch() 就是这个原因。有一次我忘了 catch,网络慢时整个页面卡死,用户骂疯了。
  2. 阈值别设太死:THRESHOLD 设成 5 是经验值,但不同场景要调。比如搜索框可能用户真会快速删改,这时候阈值得放宽到 10+。建议先灰度观察几天日志再定。
  3. 别信前端数据:所有上报的数据,后端必须二次校验。前端能被绕过,比如有人直接调 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 篡改,后续会继续分享这类博客。有更优的实现方式欢迎评论区交流——特别是怎么平衡性能和检测粒度,我现在还在优化。

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论