从裸奔到加固:我的校园论坛网络安全实战

本文记录了一个大二学生在开发校园论坛时,为即将开始的班级试点进行网络安全加固的全过程。如果你也在独立做全栈项目,希望这些经验能帮你少踩几个坑。

前言

我的校园论坛(江农论坛)已经完成了核心功能开发------帖子发布、评论互动、分区浏览、树洞匿名、首页推荐、个人主页、管理员审核、白名单注册。在准备向全班同学推广之前,我意识到一个严重的问题:项目一直在"裸奔"

后端 cors() 允许所有来源访问,没有频率限制,请求体大小不受控,HTTP 安全头一个都没配。这就像一个房子装修好了,但门窗全开着。

今天的目标很明确:在试点之前,把安全加固做完。

一、CORS 白名单:别让所有人都能调你的 API

问题

项目初期为了开发方便,后端直接用了 app.use(cors()),这行代码的意思是"允许任何网站跨域请求我的 API"。在生产环境里,这意味着任何网站都可以用 JavaScript 调用你的接口,用你用户的身份发帖、评论。

解决方案

改成只允许自己的域名和本地开发地址:

javascript 复制代码
app.use(cors({
  origin: [
    'https://www.aoliforum.me',
    'https://aoliforum.me',
    'http://localhost:5173'
  ],
  credentials: true
}))

踩坑点

如果你的前端和后端不在同一个域名下(我的前端在 Vercel,后端在 Railway),并且前端请求时带了 Authorization 头,那么 credentials: true 是必须的。否则浏览器不会发送 Cookie 和 Authorization 头。


二、请求体大小限制:防止恶意超大请求

问题

Express 默认不限制请求体大小。如果有人恶意发送一个巨大的 JSON 请求,你的服务器可能会内存溢出或响应变慢。

解决方案

javascript 复制代码
app.use(express.json({ limit: '1mb' }))

这行代码限制所有请求体不超过 1MB。对于论坛场景(纯文本帖子、评论),1MB 已经非常充裕。如果以后接入了图片上传,图片走七牛云直传,不会经过这个限制。


三、接口防刷:别让人暴力破解和批量注册

问题

登录接口如果没有任何限制,攻击者可以用脚本暴力破解密码。注册接口没限制,可以批量注册垃圾账号。

解决方案

express-rate-limit 对不同接口设置不同的频率限制:

javascript 复制代码
const rateLimit = require('express-rate-limit')

// 登录接口:15分钟最多10次
const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 10,
  message: { error: '登录尝试过多,请15分钟后再试' }
})
app.use('/api/users/login', loginLimiter)

// 注册接口:1小时最多3次
const registerLimiter = rateLimit({
  windowMs: 60 * 60 * 1000,
  max: 3,
  message: { error: '注册请求过于频繁,请稍后再试' }
})
app.use('/api/users/register', registerLimiter)

踩坑点

app.use顺序非常重要 。限速中间件必须放在路由注册之前,否则不会生效。我一开始把 rateLimit 的代码放在了路由注册之后,测试时发现完全没限制,排查了半天才发现是顺序问题。


四、Helmet 安全头:给你的 HTTP 响应穿上盔甲

问题

Express 默认不会添加任何安全相关的 HTTP 头。这意味着你的网站容易被点击劫持、MIME 类型嗅探、XSS 等攻击。

解决方案

安装 helmet 并配置:

javascript 复制代码
const helmet = require('helmet')

app.use(helmet({
  crossOriginResourcePolicy: { policy: 'cross-origin' },
  contentSecurityPolicy: false
}))

踩坑点

helmet 默认会启用 CSP(内容安全策略),它会限制页面可以加载哪些来源的资源。但我的前端和后端不同域,前端需要跨域请求后端 API,默认的 CSP 策略会拦截这些请求,导致论坛完全不可用。

解决方案是关闭 CSP(contentSecurityPolicy: false),同时把 crossOriginResourcePolicy 设为 cross-origin,允许跨域资源加载。这不是最佳实践,但对于前后端分离的小项目来说,这是最务实的做法。


五、环境变量与依赖安全

环境变量

检查 .gitignore 是否包含了 .env 文件:

bash 复制代码
backend/.env
.env

然后用 git log 确认历史记录里没有误提交过 .env 文件。如果提交过,需要立即更换数据库密码和 JWT 密钥。

依赖安全

运行 npm audit 检查依赖漏洞。我的项目发现 mongo-express 有 3 个低危漏洞。mongo-express 是 MongoDB 的 Web 管理界面,只是一个开发工具,不暴露在公网,但为了零漏洞,我直接卸载了它,用 MongoDB Compass 和 Atlas 网页界面替代。


总结与感受

这次安全加固让我意识到:功能开发和安全加固是两件完全不同的事。 功能开发是"让东西跑起来",安全加固是"让东西不被搞垮"。前者追求速度,后者追求防御深度。

分享几点体会:

  1. CORS 白名单是底线 :永远不要在生产环境用 cors() 通配符。这是最低成本的防护,也是最容易被忽视的。
  2. 限速配置要区分场景:登录、注册、发帖、评论,不同接口的风险不同,限速策略也应该不同。一刀切的全局限制要么太松(登录被刷),要么太紧(正常用户被误伤)。
  3. Helmet 不是"装上就行":它默认的 CSP 策略会让前后端分离的项目挂掉。你需要理解每个安全头的作用,而不是盲目装包。
  4. 环境变量泄露是不可逆的 :一旦 .env 被提交到 Git,你的密码就永远留在历史记录里了。唯一的补救是立即更换密钥。
  5. 依赖安全要定期检查npm audit 只需要几秒钟,但它能在漏洞被利用之前提醒你。

项目状态更新:

  • 在线地址:aoliforum.me
  • 已完成功能:帖子发布、评论互动、游客模式、分区浏览、树洞匿名、首页推荐、个人主页、管理员审核、白名单注册、联系通道
  • 已完成安全加固:CORS 白名单、接口防刷、Helmet 安全头、请求体限制、环境变量与依赖安全
  • 待完成:消息通知

如果你也在独立做全栈项目,欢迎评论区交流你的安全实践。

相关推荐
晓杰'7 小时前
Balatro后端进阶(1):自定义NestJS WebSocket Adapter实现消息拦截
后端·websocket·typescript·node.js·游戏开发·nestjs·wsadapter
zyl837219 小时前
Express快速上手
https·node.js·express
梦无矶9 小时前
nrm自动设置npm镜像源
前端·npm·node.js
网络点点滴9 小时前
Node.js的核心:事件循环
node.js
zyl8372110 小时前
Node.js 安装
node.js
梦无矶10 小时前
快速设置npm默认源为国内全局镜像源
前端·npm·node.js
王木风1 天前
终端里的编程副驾:DeepSeek-TUI-项目深度拆解,实测与原理分析
linux·运维·人工智能·rust·node.js
菜泡泡@1 天前
npm 安装pnpm之后运行pnpm -v查询报错
前端·npm·node.js