v7.9.0:找回密码上线——一枚邮箱验证码背后的 5 个安全设计

v7.9.0:找回密码上线——一枚邮箱验证码背后的 5 个安全设计

狸花云控制台今天上线了「找回密码」。听起来是个小功能:填邮箱、收验证码、设新密码,三步完事。但真正做起来,难点不在流程,而在怎么不让这个功能变成攻击者的工具。这篇记录一下 v7.9.0 的实现,以及同天发布的侧栏角色分层和阶梯定价。

一、找回密码:流程只有三步,防线有五层

前端入口很克制——登录框下方一行「忘记密码?」,点开是弹窗,邮箱、验证码、新密码依次出现。后端两个接口:


POST /api/forgot/send-code   # 发验证码
POST /api/forgot/reset       # 校验 + 改密码

五个安全设计,每一条都对应一类真实攻击:

防线 参数 防什么
防邮箱枚举 未注册邮箱也返回「如果该邮箱已注册,验证码已发送」 攻击者批量探测哪些邮箱注册过
验证码时效 10 分钟过期 拦截到旧邮件也无法利用
尝试次数 错误 5 次作废 暴力枚举 6 位数字(理论百万分之一/次)
发送冷却 60 秒内不可重发 邮件轰炸、刷接口
一次一用 重置成功后立即删除记录 验证码复用

其中防枚举是最容易被忽略的。直觉写法是查不到邮箱就返回 404「该邮箱未注册」——方便、友好,但等于给攻击者开了一个免费的用户名册查询接口。现在的做法是统一话术,只是不真发信,同时在审计日志里记一笔 forgot-send-skip,管理员侧依然能看到异常探测行为。


if (!u || u.status !== 'active') {
  auditLog(req, 'auth', 'forgot-send-skip', { detail: email, ok: false })
  return ok(res, { ok: true, message: '如果该邮箱已注册,验证码已发送' })
}

新密码的规则也收紧了:至少 8 位,必须同时包含字母和数字。所有成功重置都会写审计日志(forgot-reset),谁在什么时间重置了密码,可追溯。

二、侧栏角色分层:三种人看到三个控制台

之前所有登录用户看到的侧栏是一样的,只是部分页面进去后显示「无权限」。这在逻辑上没错,体验上很糟——用户能看到「节点管理」却点不进去,只会觉得系统坏了。

v7.6.0 把侧栏按角色拆成三层:

  • 普通用户:我的空间(服务器 / 工具箱 / 订阅链接 / 域名)+ 购买与服务
  • 运维(operator):额外看到运营中心(看板 / 代码管理 / VLESS 管理)
  • 管理员:再额外看到基础设施(节点 / 模板)和用户与计费

不只是前端隐藏。后端同步收紧:/api/pve/guests 对普通用户剥离节点信息,/api/pve/status 直接返回空。前端隐藏是体验,后端过滤才是安全——这条原则这次彻底落实了。

三、自定义套餐:阶梯定价上线

商城新增「自定义配置」,CPU / 内存 / 磁盘 / 时长自由组合。定价采用阶梯而非线性——线性定价(1 核 5 元、8 核 40 元)会鼓励用户买一堆小机器而不是一台大机器,对宿主机调度是灾难。阶梯价让大单更划算:


CPU:  1核¥5  2核¥9  4核¥16  8核¥28
内存: 1G¥2   2G¥4   4G¥7    8G¥12   16G¥22
时长: 月×1   季×2.7(9折)  年×9.6(8折)

技术上有两个点值得一提:

1. 临时套餐不落库。自定义配置生成 planOverride 直接注入下单流程,不污染 plans 列表,管理页不会被一堆一次性配置淹没。

2. 下单前做容量预检。按目标节点剩余磁盘(留 5% 缓冲)判断能否开通,不足直接返回「无库存」,前端同时禁用购买按钮——不让用户付了钱才发现开不出来。

四、顺便做的:清理 30 条僵尸设备码

代码管理里躺着 64 条设备码,盘点后发现只有 14 条关联着有效订单,20 条是 VLESS 待分配库存,剩下 30 条是测试残留和已退款/已取消订单的遗留。全部备份后清理,代码总数从 64 降到 34。

这类「数据卫生」平时不起眼,但设备码列表是运营看板的数据源——垃圾数据不清,所有统计都是假的。

小结

v7.9.0 一天的量:一个安全向的新功能(找回密码)、一次权限模型的重构(角色分层)、一个商业化能力(阶梯定价)、一轮数据清理。控制台版本号、更新日志与本文同步公开。

狸花网络 · 让每一台设备都有身份 🐾

💬 留下你的爪印