django-axes是最直接可控的暴力破解防护方案,需正确配置AXES_FAILURE_LIMIT=5、AXES_LOCK_OUT_AT_FAILURE=True和AXES_COOLOFF_TIME=600,并确保AxesMiddleware置于SessionMiddleware之后、AuthenticationMiddleware之前,且AxesBackend排在AUTHENTICATION_BACKENDS首位。

django-axes 是目前最直接、最可控的修复方案。它不依赖你重写登录逻辑,也不要求你手动记录 IP 或封禁状态——只要正确接入,就能在 5 分钟内让暴力破解者反复撞墙。
为什么 AXES_FAILURE_LIMIT 设成 5 还被绕过?
常见错误是只改了限制次数,却没配 AXES_LOCK_OUT_AT_FAILURE 或 AXES_COOLOFF_TIME。
AXES_FAILURE_LIMIT = 5 只表示“失败 5 次后触发锁定”,但是否真锁、锁多久,取决于另外两个开关:
- AXES_LOCK_OUT_AT_FAILURE = True(默认 False,不设就等于没锁)
- AXES_COOLOFF_TIME = 600(单位秒,即 10 分钟;设为 None 则永久锁定)
- 如果用的是 IP 级锁定(默认),还要注意:Nginx 或 CDN 后的真实客户端 IP 可能被覆盖,需同步配置 AXES_IPWARE_PROXY_COUNT 和 AXES_IPWARE_PROXY_HEADERS
axes.middleware.AxesMiddleware 加在哪儿才生效?
必须加在 SessionMiddleware 之后、AuthenticationMiddleware 之前。顺序错会导致:
- 用户未登录时无法识别会话,axes 拿不到 session_key,误判为新请求
- 中间件加载顺序颠倒后,AXES_RESET_ON_SUCCESS = True 失效,成功登录也不清计数
标准顺序示例:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'axes.middleware.AxesMiddleware', # ← 必须在这儿
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
]登录接口返回 403 却没进 axes 日志?
这通常意味着请求根本没走到 AxesBackend。检查三件事:
- AUTHENTICATION_BACKENDS 是否把 axes.backends.AxesBackend 放在第一位?它必须优先于 ModelBackend,否则失败直接由后者处理,axes 完全无感知
- 登录视图是否用了 login() 函数?如果手写了 authenticate() + login() 流程,但漏掉 request 参数传给 authenticate(),axes 就拿不到上下文
- 是否启用了 AXES_ONLY_USER_FAILURES = True?该选项会让 axes 只统计已知用户名的失败(比如攻击者瞎猜用户名,就不会计入)——这虽可降低误伤,但也削弱防护力度
生产环境里 axes 记录暴涨,数据库变慢怎么办?axes 默认把所有尝试存进数据库,高频攻击下容易拖垮 PostgreSQL 或 MySQL。
可行解法:
- 把 AXES_HANDLER = 'axes.handlers.cache.AxesCacheHandler',改用 Redis 缓存存储计数(需提前装 django-redis 并配置 CACHES)
- 设置 AXES_META_TRUNCATE_LENGTH = 255,避免长 User-Agent 或 Referer 写满字段
- 定期清理:python manage.py axes_reset 或按需调用 axes.reset 信号,不要等表膨胀到 GB 级再动手
axes.middleware.AxesMiddleware 加在哪儿才生效?
必须加在 SessionMiddleware 之后、AuthenticationMiddleware 之前。顺序错会导致:
- 用户未登录时无法识别会话,axes 拿不到 session_key,误判为新请求
- 中间件加载顺序颠倒后,AXES_RESET_ON_SUCCESS = True 失效,成功登录也不清计数
标准顺序示例:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'axes.middleware.AxesMiddleware', # ← 必须在这儿
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
]登录接口返回 403 却没进 axes 日志?
这通常意味着请求根本没走到 AxesBackend。检查三件事:
- AUTHENTICATION_BACKENDS 是否把 axes.backends.AxesBackend 放在第一位?它必须优先于 ModelBackend,否则失败直接由后者处理,axes 完全无感知
- 登录视图是否用了 login() 函数?如果手写了 authenticate() + login() 流程,但漏掉 request 参数传给 authenticate(),axes 就拿不到上下文
- 是否启用了 AXES_ONLY_USER_FAILURES = True?该选项会让 axes 只统计已知用户名的失败(比如攻击者瞎猜用户名,就不会计入)——这虽可降低误伤,但也削弱防护力度
生产环境里 axes 记录暴涨,数据库变慢怎么办?axes 默认把所有尝试存进数据库,高频攻击下容易拖垮 PostgreSQL 或 MySQL。
可行解法:
- 把 AXES_HANDLER = 'axes.handlers.cache.AxesCacheHandler',改用 Redis 缓存存储计数(需提前装 django-redis 并配置 CACHES)
- 设置 AXES_META_TRUNCATE_LENGTH = 255,避免长 User-Agent 或 Referer 写满字段
- 定期清理:python manage.py axes_reset 或按需调用 axes.reset 信号,不要等表膨胀到 GB 级再动手
axes 记录暴涨,数据库变慢怎么办?axes 默认把所有尝试存进数据库,高频攻击下容易拖垮 PostgreSQL 或 MySQL。
可行解法:
- 把 AXES_HANDLER = 'axes.handlers.cache.AxesCacheHandler',改用 Redis 缓存存储计数(需提前装 django-redis 并配置 CACHES)
- 设置 AXES_META_TRUNCATE_LENGTH = 255,避免长 User-Agent 或 Referer 写满字段
- 定期清理:python manage.py axes_reset 或按需调用 axes.reset 信号,不要等表膨胀到 GB 级再动手
真正容易被忽略的点是:axes 的锁定粒度默认是 IP,但现代应用大多跑在 Nginx + uWSGI 下,所有请求看起来都来自 127.0.0.1。不配透传真实 IP,等于锁了个寂寞。


















