返回
1032 字
5 分钟
0 次阅读
给外呼软件的后端加一层锁

易杰云呼是个给做电话外呼的人用的软件,前端是一个单页应用,后端是 Node.js + Express + SQLite。 前段时间我把后端整个加固了一遍,这篇记一下都改了什么、为什么这么改。

先说背景:它跑在一台 2 核 2G 的服务器上,带宽 8Mbps,跑不起来太复杂的东西。 登录接口暴露在公网上,谁都能试密码。

第一件事:加图形验证码#

光靠限流不够,得让”机器批量试密码”这件事本身变麻烦。所以加了个图形验证码。

做的时候有几个细节是特意处理的:

  • 6 位,去掉 0、O、1、I、L 这几个容易看错的字符 —— 不然用户自己都输不进去。
  • 每个字符随机旋转、随机颜色、随机大小,再叠 5 条干扰线和 30 个噪点。
  • 5 分钟过期,一次性,用完即废;大小写不敏感。

直接输出 SVG 而不是图片,省掉了图片编码那一步,服务器压力小一点。

第二件事:四层限流#

原来的限流只有一层,明显不够。现在从外到里是四层:

第 1 层 全局 所有 IP 加起来 1 分钟超过 1000 次 → 全局关掉登录 5 分钟
第 2 层 单 IP 同一个 IP 1 分钟 5 次
第 3 层 验证码 同一个 IP 1 分钟最多取 20 次验证码
第 4 层 试错 同一个 IP 1 分钟内验证码错 5 次 → 禁 5 分钟

登录的顺序也改了,现在是: 全局限流 → 单 IP 限流 → 验证码校验 → 密码校验。 验证码放在密码前面,等于在最外圈就先把机器挡掉,不让它消耗到密码比对那一步。

踩的坑:限流本身把服务器拖卡了#

这个坑挺典型的。我一开始的限流是写文件的:每次登录请求都去 readFileSync 读一遍、再 writeFileSync 写回去。

结果就是登录明显变卡 —— 因为同步读写会把整个 Node 的事件循环堵住。 更糟的是,它本身还是个 DoS 漏洞:只要有人一直请求,磁盘就一直被读写。

后来改成了纯内存的 Map 计数,问题就没了。内存表也设了硬上限,超过一万条就删最旧的,防止无限增长。

开关防连点#

这个是给用户用的,不是给攻击者用的。设置页里有几个开关,有人会一直点, 点一次发一次请求,服务器就被刷。

现在的规则是:同一个用户每点满 10 次,锁 10 秒,返回一句”手速太快,稍后再试 ⚡”。 纯内存实现,按 userId 记,不落盘。

一个历史遗留问题:设备列表里 50 个”在线”#

这个困扰我挺久。用户反复登录之后,设备列表里会堆出一堆重复的在线设备, 因为每次登录都会发一个新 token,旧的没作废。

改法很直接:登录成功的时候,先把这台设备的旧 token 全部标成无效,只留最新一条。

另外管理员那边的设备列表也改了查询方式,用 JOIN 去取每个设备最新的一条记录, 这样历史脏数据也不会把界面撑爆。

还剩一个没改完的#

联系人批量导入那里还有个卡顿没解决:现在是一行一行循环插入,而且插入还没结束就提前 把语句收尾了,号码多的时候既卡又可能丢数据。

要改成分批插入、等这一批真的写完了再往下走。这个我先记着,下次处理。


这一轮改完,后端从原来的一层限流变成了四层,验证码、防连点、token 治理都补上了。 整个过程最值得记的一条是:限流这种东西,自己也可能成为被攻击的点 —— 我第一版就是因为写文件,反而把服务器拖垮了。

这篇文章讲的东西,可以在这里下载

全部东西都在下载区, 包括模组、地图和软件。

给外呼软件的后端加一层锁
https://liyuanjie.com/posts/ninth-post/
作者
Liyuanjie
发布于
2026-08-23
许可协议
CC BY-NC-SA 4.0
这篇被看了 0 次