React登录限制如何防止频繁尝试导致接口被攻击?
我给登录表单加了防抖和错误次数限制,但测试时发现攻击者还是能不断重试,这是为什么?
现在用useState记录错误次数,超过3次就禁用按钮,还用了防抖处理:
const Login = () => {
const [attempts, setAttempts] = useState(0);
const handleSubmit = useCallback(debounce(async (e) => {
e.preventDefault();
try {
await loginApi(loginForm);
} catch (err) {
setAttempts(prev => prev +1);
if(attempts >=3) disableForm();
}
}), [loginForm]);
return (
<form onSubmit={handleSubmit}>
{/* 表单字段 */}
{attempts <3 ? <button>登录</button> : '尝试次数过多'}
</form>
);
};
但用Postman疯狂请求接口时,错误次数没被记录,后端说被攻击了。前端的这种限制根本没起作用啊,是不是应该加验证码?或者服务端也要做限流?
attempts计数和按钮禁用逻辑,所以你看到的“限制”根本不起作用。要真正防止暴力破解攻击,必须在**服务端做限流和验证机制**,前端的限制只是锦上添花。下面是关键步骤:
### 1. 后端必须做接口限流(Rate Limit)
- 比如每个 IP 每分钟最多请求登录接口 10 次
- 超出限制直接返回 429
- 可用中间件如 Express 的
rate-limiter-flexible,或者用 Nginx 限流### 2. 登录失败次数过多,要记录在服务端
- 用 Redis 记录用户/IP 的失败次数
- 比如连续失败 5 次,锁定账户或返回验证码挑战
- 前端的
attempts控制只是辅助,不能作为唯一限制### 3. 加验证码(推荐)
- 登录失败达到一定次数后触发验证码(reCAPTCHA、极验、点选验证码等)
- 验证码必须服务端验证通过才允许继续登录流程
### 4. 避免爆破账户,登录接口不要暴露是否存在该用户
- 无论用户名是否存在、密码是否正确,都统一返回“用户名或密码错误”
- 避免攻击者用来探测有效账户
---
你现在的 React 代码虽然加了防抖和尝试次数,但这些状态都保存在浏览器内存里,攻击者绕过去非常容易。你可以在前端保留这些逻辑提升体验,但一定要加后端防护,不然就像“给大门装了锁,窗户却开着”。
建议你和服务端一起改,加限流和验证码,这才是完整的防御。