React登录限制如何防止频繁尝试导致接口被攻击?

UX凌薇 阅读 233

我给登录表单加了防抖和错误次数限制,但测试时发现攻击者还是能不断重试,这是为什么?

现在用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疯狂请求接口时,错误次数没被记录,后端说被攻击了。前端的这种限制根本没起作用啊,是不是应该加验证码?或者服务端也要做限流?

我来解答 赞 13 收藏
二维码
手机扫码查看
2 条解答
夏侯玉浩
你这代码在前端做限制,防个寂寞呢。

攻击者用Postman直接调接口,根本不经过你这套React代码,useState记多少次都没用。前端的限制只能防小白,防不了攻击。

正确的做法是服务端限流,给你个Node.js/Express的例子:

const rateLimit = require('express-rate-limit');

// 登录接口限流
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 5, // 最多5次尝试
message: { code: 429, msg: '尝试次数过多,请稍后再试' },
standardHeaders: true,
legacyHeaders: false,
});

app.post('/api/login', loginLimiter, loginHandler);


或者用Redis实现更精准的IP+账号维度的限流:

const redis = require('redis');
const client = redis.createClient();

async function checkLoginLimit(ip, username) {
const key = login:${ip}:${username};
const count = await client.incr(key);

if (count === 1) {
await client.expire(key, 900); // 15分钟过期
}

if (count > 5) {
throw new Error('尝试次数过多');
}

return count;
}


验证码也建议加上,图形验证码或滑块验证都行,能有效防止暴力破解。前端那套限制保留着当用户体验优化就行,别当安全手段用。

总结一下:前端限制是给正常用户看的,安全防护必须在后端做。
点赞 1
2026-03-01 18:14
百里红运
你这个问题很常见,前端防抖和错误次数限制其实只是用户体验层面的措施,**根本防不住接口被攻击**。攻击者用 Postman 或脚本直接调用登录接口,完全绕过了你前端的 attempts 计数和按钮禁用逻辑,所以你看到的“限制”根本不起作用。

要真正防止暴力破解攻击,必须在**服务端做限流和验证机制**,前端的限制只是锦上添花。下面是关键步骤:

### 1. 后端必须做接口限流(Rate Limit)
- 比如每个 IP 每分钟最多请求登录接口 10 次
- 超出限制直接返回 429
- 可用中间件如 Express 的 rate-limiter-flexible,或者用 Nginx 限流

### 2. 登录失败次数过多,要记录在服务端
- 用 Redis 记录用户/IP 的失败次数
- 比如连续失败 5 次,锁定账户或返回验证码挑战
- 前端的 attempts 控制只是辅助,不能作为唯一限制

### 3. 加验证码(推荐)
- 登录失败达到一定次数后触发验证码(reCAPTCHA、极验、点选验证码等)
- 验证码必须服务端验证通过才允许继续登录流程

### 4. 避免爆破账户,登录接口不要暴露是否存在该用户
- 无论用户名是否存在、密码是否正确,都统一返回“用户名或密码错误”
- 避免攻击者用来探测有效账户

---

你现在的 React 代码虽然加了防抖和尝试次数,但这些状态都保存在浏览器内存里,攻击者绕过去非常容易。你可以在前端保留这些逻辑提升体验,但一定要加后端防护,不然就像“给大门装了锁,窗户却开着”。

建议你和服务端一起改,加限流和验证码,这才是完整的防御。
点赞 11
2026-02-04 12:01