You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何用Django REST Throttling防范暴力攻击并临时封禁特定用户

使用Django REST Throttling防范暴力攻击及封禁指定用户

一、用Django REST Throttling防范暴力攻击

DRF自带的节流组件天生就是用来限制请求频率的,刚好能应对暴力攻击场景,咱们可以从这几个方向配置:

  1. 用默认节流类快速全局生效
    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]
        # 登录逻辑...
    
  2. 自定义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默认节流是限制频率,不是直接封禁,但咱们可以自定义节流类实现这个需求,完全不用第三方包:

  1. 自定义封禁校验节流类
    用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
    
  2. 给视图绑定封禁校验
    可以全局配置让所有视图生效,也可以给特定视图单独配置:

    # 全局配置(settings.py)
    REST_FRAMEWORK = {
        'DEFAULT_THROTTLE_CLASSES': [
            'yourapp.throttling.BanUserThrottle',
            # 其他节流类...
        ]
    }
    
    # 单个视图配置
    class ProtectedResourceView(APIView):
        throttle_classes = [BanUserThrottle]
        # 视图逻辑...
    
  3. 手动封禁用户的实现方式
    咱们可以写一个管理命令或者后台视图来手动触发封禁,比如:

    # 管理命令示例(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

火山引擎 最新活动