bigywater.tech
Flask · 129

Rate Limiting

给登录接口限流,该按 IP 还是按用户名?成功的登录要不要计数?限流本身会不会变成攻击面?这篇用 Flask-Limiter 把四种策略的结果摆在一起,只验证限流这一层的行为。

[200, 200, 200, 429, 429]
成败都计数时,正常用户连续 5 次成功登录的结果
429
按用户名限流时,真正的账号主人也被挡住的状态码
2 层
用户名层加 IP 层的叠加限流

成败都计数

实测 · 本机执行输出
  同一个 IP 连续 5 次正确登录: [200, 200, 200, 429, 429]

上一篇:CORS 安全边界;下一篇:密码哈希与密码升级。

第 76 篇讲 Flask-Limiter 的基本用法,第 111 篇讲自己实现的令牌桶,这一篇讲登录保护的策略取舍。

只计失败的尝试

实测 · 本机执行输出
  连续 5 次正确登录: [200, 200, 200, 200, 200]
  同一个 IP 连续 4 次错误密码: [401, 401, 401, 429]
  之后用正确的密码登录: 429 (被限流挡住,即使密码正确)

按用户名限流

实测 · 本机执行输出
  对 ann 用 5 个不同的 IP 各猜 1 次: [401, 401, 401, 429, 429]
  这时 bob 用同样的 IP 登录: 200 (别的账号不受影响)
  但真正的 ann 此时也被挡住: 429 (攻击者可以借此让账号暂时无法登录——这是按用户名限流的副作用)

两层叠加

实测 · 本机执行输出
  同一个 IP 猜 ann 4 次: [401, 401, 401, 429]
  同一个 IP 再换 10 个不同的用户名各猜 1 次: [401, 401, 401, 401, 401, 401, 401, 429, 429, 429]

被限流时的响应

实测 · 本机执行输出
  第 4 次 → 429 {} | 正文: <!doctype html> <html lang=en> <title>429 Too Many Requests</title> <h

分步演示

登录限流
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.7 / Flask 3.1.3 / Werkzeug 3.1.9 / Jinja2 3.1.6 / SQLAlchemy 2.1.1 / gunicorn 26.2.0(都装在自己的虚拟环境里);大多数实验用 Flask 的 test_client(直接调用 WSGI 应用,不经过网络),需要真实 HTTP 时另起 gunicorn 或开发服务器(端口 9600 以上,本机 127.0.0.1);计时用 time.perf_counter,数字每次运行会有小幅抖动。Flask-Limiter 4.1.1、memory:// 存储
    • 没有验证:分布式部署下用 redis 存储的一致性、验证码与渐进式延迟(退避)等替代方案、对密码找回与注册接口的限流、真实攻击流量下的内存占用
    京ICP备2026067502号-1京公网安备11010502063487号