我做了5年前端开发,去年转型全栈时,用Vue3+Node.js+Express搭建了一个用户反馈收集平台。原本想通过这个项目积累全栈经验,没想到上线第3天就出现了服务故障:凌晨收到服务器告警,登录后发现CPU使用率100%、内存占用98%,服务已经无法响应,后台有200多条用户反馈没能同步,数据库中还出现了1万多条乱码数据。
这次故障让我意识到,前端转全栈时,安全防护是很容易被忽视的环节。我把整个事件的复盘过程、试错经历和最终解决方案整理出来,希望能给刚转型全栈的前端同行提供一些参考。
一、全栈新手的常见疏忽:只关注功能实现,忽视安全防护
这个用户反馈平台的架构比较基础:部署在阿里云1核2G轻量服务器上,用Nginx反向代理,Node.js(Express)提供API服务,MongoDB存储数据,前端静态资源放在OSS。上线前我测试了前端交互、接口联调和数据校验,还用JMeter模拟了100并发请求,当时没发现问题,现在看来,这些测试只覆盖了功能层面,没考虑安全防护。
事后通过PM2日志复盘,发现了故障的主要原因:
- 接口未做限流防护:/api/feedback接口没有设置访问频率限制,被恶意脚本每秒发起50多次请求,导致Express事件循环阻塞,正常请求无法处理;
- 后端缺少参数二次校验:前端用Element Plus做了表单格式校验,但后端没有同步校验。攻击者通过Postman提交含特殊符号的参数,导致MongoDB插入乱码数据,最终引发数据库锁表;
- 对异常请求认知不足:日志中存在大量携带"../"路径遍历、"$eval"脚本注入的请求,我之前做前端时没接触过这类安全问题,不知道该如何处理。
我花了3小时才定位到问题根源。作为前端转全栈的新手,我对服务器安全和恶意请求识别不熟悉,只能通过搜索"Node.js服务CPU100%"、"MongoDB乱码数据"等关键词查找解决方案,后来在掘金上看到有同行提到用WAF做防护,才意识到这是之前遗漏的关键环节。
二、防护方案试错过程:从自研到选型,找到适合的工具
为了解决安全问题,我花了一周时间测试了3类防护方案,过程中踩了不少坑,也逐渐明确了适合全栈新手的解决方案。
试错1:自研Node.js拦截中间件——效果有限且耗性能
作为前端开发,我的第一反应是通过代码解决,于是参考网上的教程写了一个简单的拦截中间件,通过正则匹配关键词拦截恶意请求,核心代码如下:
// 简单的请求拦截中间件
app.use((req, res, next) => {
const dangerousReg = /$eval|/..|select|insert/gi;
const reqBody = JSON.stringify(req.body);
if (dangerousReg.test(reqBody)) {
return res.status(403).send("非法请求");
}
next();
});
实际使用后发现这个方案存在明显问题:一是正则规则简单,攻击者用全角字符等方式就能绕过;二是中间件消耗资源较高,100并发请求就使接口响应延迟从50ms增至300ms;三是没有限流功能,恶意请求仍会占用大量服务器资源。尝试优化两天后效果仍不理想,只能放弃这个方案。
试错2:云厂商免费WAF——适配性不足,满足不了需求
之后我尝试了某云厂商的免费WAF,部署过程比较简单,通过控制台操作几步就能完成,但使用一天后发现了三个问题:
- Node.js接口适配问题:WAF默认将Express的"application/json"请求判定为异常格式,误拦率达到30%,导致用户正常反馈无法提交;
- 限流功能单一:仅支持按IP限流,攻击者通过代理IP池切换就能绕过限制;
- 日志排查不便:WAF日志与PM2日志无法联动,拦截记录缺少详细上下文,出现问题后难以定位原因。
正当我纠结如何解决这些问题时,在前端转全栈交流群里,有同行推荐了雷池社区版WAF,提到它对Node.js生态适配较好,而且是免费的。我抱着尝试的心态开始测试这个工具。
试错3:雷池社区版——部署简单,适配性符合需求
实际使用后发现,这个工具确实比较适合全栈新手。我按照官网的"Node.js服务适配指南"操作,全程没有请教后端同事,大概1小时就完成了部署,防护效果也达到了预期。
三、雷池WAF部署过程:Nginx+Node.js环境适配步骤
雷池社区版基于Docker部署,对前端开发者来说门槛不高。下面以CentOS 7.9系统为例,分享具体的部署步骤:
步骤1:Docker部署WAF,命令可直接复用
不需要手动安装复杂依赖,将以下3条命令依次复制到服务器终端执行,即可完成部署:
// 1. 安装Docker
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
// 2. 启动Docker服务并设置开机自启
systemctl start docker && systemctl enable docker
// 3. 部署雷池社区版
docker run -d --name leichi -p 80:80 -p 443:443 -v /etc/leichi:/etc/leichi --restart=always leichi/waf:community
执行完成后,输入"docker ps"命令,若看到"leichi"容器状态为"Up X seconds",说明部署成功。整个过程比搭建Express服务还要简单。
步骤2:关联服务,可视化配置无需修改代码
雷池提供了可视化控制台,不需要修改Nginx或Node.js配置,通过界面操作就能完成服务关联:
- 获取登录密码:执行"docker logs leichi | grep 初始密码",复制输出的密码;
- 登录控制台:在浏览器中输入服务器公网IP,使用默认账号"admin"和获取到的初始密码登录,首次登录需修改密码;
- 关联服务:点击左侧"网站管理→添加网站",重点配置以下三个字段: - 网站域名:填写自己的域名或服务器公网IP; - 后端服务地址:填写服务器内网IP(阿里云控制台"概览"页可查看); - 后端服务端口:填写Node.js服务运行的端口(我使用的是3000端口)。
填写完成后点击"保存",系统会自动生成适配Node.js的防护规则,无需额外配置,对前端开发者比较友好。
四、针对性防护配置:解决故障问题并提升服务稳定性
部署完成后,针对之前服务故障中暴露的问题,我做了三项关键配置,不仅解决了安全隐患,服务稳定性也有了提升。
配置1:接口限流与恶意请求拦截,解决资源占用过高问题
进入雷池控制台"CC防护→添加规则",针对核心接口做了两两层防护配置配置:
- 按用户标识限流:前端为每个用户生成唯一的user-token,雷池支持按请求头中的"user-token"设置限流规则,我配置的是"单token每分钟最多请求20次"。这种方式比按IP限流更精准,能避免攻击者通过代理IP绕过限制;
- 恶意请求识别:启用"Node.js接口防护模板",系统会自动识别脚本注入、路径遍历等异常请求,不需要手动编写正则规则。测试时用Postman提交含"$eval"的参数,能被正常拦截,控制台会记录详细的拦截日志。
配置2:参数校验增强,避免无效数据写入数据库
利用雷池的"参数校验"功能,针对/api/feedback接口设置字段校验规则:"content"字段不允许包含特殊符号,"contact"字段需符合手机号或邮箱格式。这相当于在后端增加了一层数据校验,比之前自研的中间件更可靠。
配置3:日志联动,提升问题排查效率
雷池的"日志中心"功能比较实用,拦截日志能与PM2日志联动,在控制台可以清晰看到拦截请求的IP、时间、请求内容及拦截原因,方便定位问题。比如有一次发现某IP频繁尝试访问/admin路径,通过日志确认是异常访问后,直接在控制台将该IP加入黑名单,避免了潜在风险。
配置效果:服务稳定性明显提升
配置完成后,我用JMeter进行压力测试,并模拟恶意请求场景,测试结果显示:
- 防护效果:恶意请求拦截率达到99.6%,脚本注入、路径遍历等异常请求均被拦截,数据库中未再出现乱码数据;
- 性能表现:1000并发请求下,接口响应时间稳定在80ms以内,CPU使用率约45%,内存占用60%,相比未防护时(100并发就出现卡顿)有明显提升;
- 误拦情况:运行一个月期间仅出现2次误拦,原因是用户反馈中包含"¥"符号(如"价格¥100"),在控制台将"¥"添加为白名单关键词后,该问题得到解决。
五、前端转全栈的几点经验总结
目前这个用户反馈平台已稳定运行半年,累计收集1.2万条用户反馈,期间经历过3次流量峰值(如产品在知乎获得推荐),服务均未出现异常。结合这次经历,我总结了三点前端转全栈的经验:
- 后端安全不能依赖前端校验:前端表单校验仅能提升用户体验,无法起到安全防护作用。后端必须单独做校验,使用WAF是成本较低的防护方案,不建议新手自研防护逻辑;
- 工具选型要适配技术栈:不同技术栈的适配需求不同,像我使用Node.js,雷池社区版的适配性就比通用型云WAF更好,能减少适配成本;
- 清晰的日志便于问题排查:新手对安全问题排查经验不足,选择日志功能完善的工具很重要,雷池的日志中心帮我解决了80%的后续问题排查需求。
对前端转全栈的开发者来说,全栈开发不只是前后端代码的简单组合,服务安全是基础保障。选择一款适配自身技术栈的防护工具,花1小时完成部署,能避免后续很多服务故障问题,从而将更多精力投入到核心功能开发中。