后台登录系统
凌晨两点十七分,后台我盯着屏幕上那个转了三分钟的登录圈,最后等来一行白字:“数据库连接超时”。系统那一刻我特别想把开发这个后台登录系统的后台人揪出来,问问他到底有没有在真实网络环境下点过登录按钮。登录 后来我自己接手了这套系统的系统维护,才明白问题出在哪儿。后台登录这件事,登录表面上看就是系统输入账号密码,点一下按钮,后台完事。登录但后台实际要跑完一整套流程:前端把密码做一次哈希,系统走 HTTPS 传到服务端,后台服务端再查数据库比对,登录比对成功生成 token,系统token 写进 Redis 或者内存,再返回给前端存到 localStorage 或者 cookie 里。每一步都可能卡住。那次超时,是因为数据库连接池设了 5 个,但并发登录请求到了 200 多——公司搞活动,运营在群里吆喝大家同时登上去抢优惠券。5 个连接排队处理 200 个请求,不超时才怪。 很多人以为后台数据库里存的就是用户注册时输的密码,顶多加个星号。不是。正常系统存的是哈希值,而且得加盐。盐就是随机字符串,每个用户不一样,跟密码拼在一起再做哈希。这样做的好处是,哪怕两个用户密码完全一样,存进去的哈希值也完全不同。我见过一个老系统,用的是 MD5 不加盐,数据库被拖库之后,彩虹表一查,一半用户的密码直接明文显示出来。那个系统后来被强制下线了,但教训摆在那儿:密码存储不能图省事。 现在推荐用 bcrypt 或者 argon2。bcrypt 有个 cost 参数,可以调计算强度。我一般设成 12,每次哈希大概要花 200 毫秒。登录的时候多花 200 毫秒用户感觉不到,但暴力破解的成本直接翻了几百倍。有人嫌慢,调到 4,那跟没加盐的 SHA256 区别不大。 登录成功之后服务端发一个 token,前端拿着它去访问其他接口。token 存哪里?localStorage 最简单,但 XSS 攻击能直接偷走。cookie 可以设 HttpOnly,JS 读不到,但得防 CSRF。我们最后选的是 HttpOnly cookie 加 SameSite=Strict,再配一个 CSRF token 放在请求头里。麻烦是麻烦,但安全。 token 的有效期也纠结过。设短了,用户老要重新登录,投诉电话打爆。设长了,token 泄露之后风险窗口太大。折中方案是 access token 设 15 分钟,refresh token 设 7 天。access token 过期了就用 refresh token 换新的,refresh token 一用就废,换发新的。这样即使 access token 被截获,15 分钟后也就没用了。refresh token 被偷了,用户下次正常刷新的时候服务端会发现旧的已经被用过,直接把整个会话踢掉。 登录失败提示不能太具体。“用户名不存在”和“密码错误”要统一成“用户名或密码错误”。不然攻击者可以拿一个字典跑一遍,先筛出哪些用户名是真实存在的。这个细节很多系统不注意,包括一些银行 App。 还有登录频率限制。同一个 IP 一分钟内失败超过 10 次,直接封 15 分钟。同一个账号连续失败 5 次,锁定 30 分钟。但锁定策略要小心,别被用来做拒绝服务攻击——攻击者故意输错别人的账号密码,把人家锁死。我们后来改成失败次数多了之后加验证码,而不是直接锁账号。 日志要记,但不能记密码。有人调试的时候图方便,把整个请求体打到日志里,密码明文躺在服务器磁盘上。这种事我见过不止一次。正确的做法是记用户名、IP、时间戳、成功还是失败,密码字段直接过滤掉。 后台登录系统这东西,写出来能跑不难,难的是跑得稳、扛得住、不出事。每次看到新闻里哪家公司又被拖库了,我第一反应就是去看他们的登录接口怎么写的。大多数时候,问题就出在那几行看起来最不起眼的代码上。密码到底存成什么样
Token 放哪儿,这是个问题
那些不起眼但真要命的小事
-
上一篇
-
下一篇
- 随机阅读
- 搜索
-
- 友情链接
-