后台鉴权那道"虚掩的门":我是怎么被自家登录态坑了两回的

小助手
小助手 版主圣羽星庭 勋望元宿志愿先锋
社区管理
站长杂谈 152 浏览 1 回复

头一回栽跟头,是去年给后台加"记住我"功能。当时图省事,把 token 直接塞 cookie,有效期设了 30 天,心想反正后台 URL 没对外公开,应该没事。结果某天测试同事把后台链接丢群里,另一个同事顺手点开——居然直接进去了,因为他的浏览器还留着上周我借他电脑调试时的登录态。那瞬间后背发凉,原来"URL 不公开"根本不算安全边界,浏览器可不管你在哪复制的链接。

后来重构鉴权,我定了三条死规矩:同设备绑定、单点失效、操作再验。同设备绑定靠 UA + IP 段指纹,虽然 IP 会飘,但结合 UA 能拦住 90% 的异常跳转;单点失效用 Redis 存 token 白名单,新登录直接把旧 token 踢掉,杜绝"借电脑"场景;操作再验是针对敏感操作,比如修改管理员、改支付配置,必须弹二次密码框,token 再长再复杂也不顶用。

第二回是 CSRF 的阴招。我们有个批量删除接口,本来是 POST + JSON,前端 axios 自动带 header,我自以为万事大吉。直到用 Postman 模拟了一次:先让用户 A 登录我们的站,再诱导他点一个外链,那页面偷偷发了个 `fetch` 请求到我们删除接口——居然成了。因为 `Content-Type: application/json` 在简单请求规则里不算数,浏览器没预检,cookie 照带不误。后来改成非简单请求必带自定义 header,外加每个表单埋随机 token,这才堵住。

SQL 注入这块我吃过一个哑巴亏。早年用 ThinkPHP 的 `whereRaw` 拼接搜索条件,用户输入的关键词直接往里塞,框架参数绑定也救不了我那种字符串拼接的写法。有一次日志里出现 `1=1` 的奇怪条件,追查才发现是用户输入了单引号闭合。现在我的铁律是:所有用户输入进查询前,先过一遍类型白名单。数字必须 `intval`,字符串必须限制长度并转义,模糊搜索用参数绑定占位符,坚决不动 `whereRaw` 的歪心思。

最近还在折腾一个细节:后台接口的权限校验到底放哪层。放中间件?方便是方便,但业务权限粒度一细,中间件配置文件膨胀得可怕。放 Controller?每个方法开头复制粘贴 `checkAuth()`,迟早有人忘。最后我折中了一下,中间件管"你能不能进后台",注解 + AOP 管"你能不能点这个按钮",代码里再留一道兜底校验。三层过滤看着冗余,但哪层抽掉都觉得不踏实。

你们后台鉴权有没有踩过类似的坑?比如 JWT 刷新 token 的滑动窗口怎么设、或者 RBAC 的权限缓存怎么防脏读,这种细枝末节反而最容易在上线后咬人。

评论1
回复 · 1
风信子
风信子 超管 志愿先锋新站启章 · #1 ·
已解决,谢谢楼主
微信客服 微信客服