注册接口的验证码比对读的是 Cookie 里的 captcha,值就是四位数答案的原文。把 Cookie 改成 1234,验证码框里也填 1234,注册直接通过。乍看像缓存或者权限的锅,追下去往往不是。

sid = request.cookies.get('captcha_id')
answer = r.get(f'cap:{sid}')
r.delete(f'cap:{sid}')

追下去是这么回事:答案放在客户端可写的位置,服务端又拿它当比对依据,等于让考生自己带答案进场。签名或者加密都没做,改起来没有门槛。真正该留在服务端的东西被推到了前端。

「验证码存 Cookie」相关的验证我通常做两遍,改完一次、隔天再看一次,确认不是临时生效。验证用真实数据走一遍,测试数据太干净,边界情况根本碰不到。

能分两步做的操作就别合成一步,中间看一眼返回值,出问题好判断。

具体做法是,答案存服务端 session 或 redis 键用一次性的随机 id 关联;提交后无论对错都删除这条记录;Cookie 只放随机的验证码 id 不放答案;给注册和登录接口加失败次数限制。

验收就看一点,改 Cookie 再提交直接提示验证码错误 同一次验证码第二次提交也失败。

作者 9823189