如何用Django REST Throttling防范暴力攻击并临时封禁特定用户
使用Django REST Throttling防范暴力攻击及封禁指定用户
一、用Django REST Throttling防范暴力攻击
DRF自带的节流组件天生就是用来限制请求频率的,刚好能应对暴力攻击场景,咱们可以从这几个方向配置:
用默认节流类快速全局生效
DRF提供了AnonRateThrottle(针对匿名用户)和UserRateThrottle(针对已认证用户)两个基础类,直接在settings里配置就能全局覆盖所有视图:# settings.py REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES': [ 'rest_framework.throttling.AnonRateThrottle', 'rest_framework.throttling.UserRateThrottle', ], 'DEFAULT_THROTTLE_RATES': { 'anon': '10/min', # 匿名用户每分钟最多10次请求 'user': '100/min' # 已认证用户每分钟最多100次请求 } }要是只想给特定视图(比如登录接口)加限制,直接在视图类里指定
throttle_classes就行:from rest_framework.throttling import AnonRateThrottle from rest_framework.views import APIView class LoginView(APIView): throttle_classes = [AnonRateThrottle] # 登录逻辑...自定义IP节流类(精准限制恶意IP)
针对匿名用户的暴力请求,按IP限制会更精准。咱们可以继承SimpleRateThrottle自定义一个IP节流类:# throttling.py from rest_framework.throttling import SimpleRateThrottle class IPThrottle(SimpleRateThrottle): scope = 'ip' def get_cache_key(self, request, view): # 若有反向代理,记得处理X-Forwarded-For头获取真实IP ip = request.META.get('REMOTE_ADDR') return self.cache_format % { 'scope': self.scope, 'ident': ip }然后在settings里添加这个类和对应的速率:
REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES': [ 'yourapp.throttling.IPThrottle', ], 'DEFAULT_THROTTLE_RATES': { 'ip': '5/min' # 同一个IP每分钟最多5次请求 } }
二、特定时长内封禁指定用户
DRF默认节流是限制频率,不是直接封禁,但咱们可以自定义节流类实现这个需求,完全不用第三方包:
自定义封禁校验节流类
用Django的缓存来存储被封禁用户的ID和到期时间,继承BaseThrottle实现核心校验逻辑:# throttling.py from rest_framework.throttling import BaseThrottle from django.core.cache import cache class BanUserThrottle(BaseThrottle): def allow_request(self, request, view): # 匿名用户跳过校验 if not request.user.is_authenticated: return True ban_key = f"banned_user_{request.user.id}" # 检查缓存中是否存在有效封禁记录 is_banned = cache.get(ban_key) if is_banned: return False # 处于封禁期,拒绝请求 return True给视图绑定封禁校验
可以全局配置让所有视图生效,也可以给特定视图单独配置:# 全局配置(settings.py) REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES': [ 'yourapp.throttling.BanUserThrottle', # 其他节流类... ] } # 单个视图配置 class ProtectedResourceView(APIView): throttle_classes = [BanUserThrottle] # 视图逻辑...手动封禁用户的实现方式
咱们可以写一个管理命令或者后台视图来手动触发封禁,比如:# 管理命令示例(management/commands/ban_user.py) from django.core.management.base import BaseCommand from django.core.cache import cache from django.contrib.auth.models import User class Command(BaseCommand): help = '封禁指定用户N分钟' def add_arguments(self, parser): parser.add_argument('user_id', type=int) parser.add_argument('minutes', type=int) def handle(self, *args, **options): user_id = options['user_id'] minutes = options['minutes'] ban_key = f"banned_user_{user_id}" # 缓存自动到期,无需手动解除 cache.set(ban_key, True, timeout=minutes*60) self.stdout.write(self.style.SUCCESS(f"用户ID {user_id} 已被封禁{minutes}分钟"))运行
python manage.py ban_user 1 60就能封禁ID为1的用户60分钟,到期后缓存自动失效,用户恢复正常访问权限。
如果需要更持久的封禁(比如永久封禁),可以建一个UserBan数据库模型存储封禁记录,在BanUserThrottle里查询数据库判断状态,不过临时封禁用缓存会更轻量高效。
内容的提问来源于stack exchange,提问作者Mr Singh




