2月很短,过个年回来就剩几个工作日。但我们团队干了一件一直想干但总是“没时间”的事——前端安全大规模排查。
为什么现在做?
说实话,安全这东西,平时总觉得“应该没问题”,等出了问题就晚了。这次趁着年初业务相对平稳,我们决定把历史欠账还上。
排查清单很简单,就8条:
text
所有用户输入都转义了?(XSS)
敏感操作加二次确认了?(CSRF)
页面禁止被iframe嵌入了?(点击劫持)
console.log删干净了?(信息泄露)
页面/按钮做了权限控制?(越权)
最近跑过npm audit吗?(依赖安全)
全站HTTPS了吗?(传输安全)
token存对地方了吗?(存储安全)
其中XSS和越权是最常见、出事最严重的。2月我们重点啃了越权这块硬骨头。
越权整改:我们本来就不差,这次更完善了
坦白说,我们在越权这块底子还可以:
- ✅ 路由守卫拦页面,没权限的直接403
- ✅ 权限指令统一管理按钮,不用到处写v-if
- ✅ 敏感操作二次确认,防误点也防CSRF
那这次改版加了什么?一个关键拼图:在菜单上配置对应接口
以前的问题:页面能看,但接口能调吗?
之前我们是这么做的:
用户登录 → 拿菜单权限 → 渲染左侧菜单 → 路由守卫拦页面
看起来没问题,但有个漏洞:菜单和接口是脱节的。
举个例子:
- 普通用户看不到“审批管理”菜单(√ 没问题)
- 但他如果知道接口地址,用Postman调
/api/order/approve(× 能调通!)
因为后端只判断“用户有没有登录”,没判断“这个接口对应用户能不能调”。
这次改了:菜单和接口绑定
核心改动就一句话:每个菜单项配置对应的接口权限,后端拦截时拿菜单做校验。
改了什么?
1. 菜单数据结构升级
javascript
// 以前的菜单
{
name: '审批管理',
path: '/approve',
icon: 'xxx'
}
// 现在的菜单
{
name: '审批管理',
path: '/approve',
icon: 'xxx',
apiPermissions: [
'/api/order/approve',
'/api/order/list?status=pending',
'/api/order/batchApprove'
] // 这个菜单下所有操作对应的接口
}
2. 最重要的是:前后口径一致了
后端收到请求/api/order/approve,拿着token查这个用户对应的菜单配置:
- 如果这个接口在用户菜单里 → 放行
- 如果不在 → 直接提示没有权限
一点体会
- 权限的核心是统一。菜单、按钮、接口,得用同一套数据源。
- 前端做体验,后端做安全。这次改版让后端能拿菜单做校验,安全防线更扎实了。
- 之前底子好,这次补短板。路由守卫+权限指令+二次确认,加上菜单配接口,算是把越权的口子全堵上了。