DRF如何保护用户注册视图 拦截非前端来源的自动化注册请求
DRF实现仅允许前端提交注册请求的防护方案
实现思路
无法100%完全区分合法前端请求和高度伪造的请求,但可以通过多层校验组合实现极高的拦截率,同时支持开发/生产环境的逻辑切换。
方案1:自定义请求头校验(核心实现)
这是最直接的区分手段,步骤如下:
- 第一步:React前端统一注入自定义请求头
在前端Axios全局配置中添加专属的私有请求头,值为预设的密钥,示例配置:
生产环境将密钥存在环境变量中,避免硬编码泄露。// React 端 Axios 全局配置 import axios from 'axios' axios.defaults.headers.common['X-Frontend-Request-Secret'] = import.meta.env.VITE_FRONTEND_REQUEST_SECRET - 第二步:DRF端自定义校验逻辑
编写自定义权限类,在校验逻辑中加入环境开关,开发环境直接放行,生产环境校验请求头:from rest_framework import permissions from django.conf import settings class IsFrontendRequest(permissions.BasePermission): def has_permission(self, request, view): # 开发环境直接放行,允许Postman测试 if settings.DEBUG: return True # 生产环境校验自定义请求头 request_secret = request.META.get('HTTP_X_FRONTEND_REQUEST_SECRET') return request_secret == settings.FRONTEND_REQUEST_SECRET - 第三步:将权限类绑定到注册接口
因为你使用的是ModelViewSet,注册对应的是create动作,所以可以重写get_permissions方法,仅给注册动作加这个校验:class UserViewSet(viewsets.ModelViewSet): serializer_class = UserSerializer permission_classes = [NotSafeMethodAndAllowAny | permissions.IsAuthenticated] def get_permissions(self): perms = super().get_permissions() # 仅注册(create)动作添加前端请求校验 if self.action == 'create': perms.append(IsFrontendRequest()) return perms # 原有逻辑保持不变 def get_queryset(self): if self.request.user.is_superuser: return User.objects.all() else: return User.objects.filter(id=self.request.user.id) @action(detail=False, methods=["get"]) def current(self, request, *args, **kwargs): return Response(self.get_serializer(request.user).data) - 第四步:配置环境变量
在生产环境的settings.py中添加配置:import os FRONTEND_REQUEST_SECRET = os.getenv('FRONTEND_REQUEST_SECRET', 'dev-default-secret')
方案2:补充CORS配置
生产环境配置django-cors-headers仅允许你的React前端域名跨域访问,虽然CORS规则对curl/Postman这类工具无效,但可以阻止其他非法网站在浏览器端调用你的注册接口:
# settings.py CORS_ALLOWED_ORIGINS = [ "https://你的React前端域名", ] # 开发环境可以加入http://localhost:3000之类的本地测试地址
方案3:补充频率限制
额外配置DRF自带的限流类,给匿名用户的注册接口加频率限制,就算请求头被泄露,也能避免批量刷注册:
首先自定义限流类:
from rest_framework.throttling import AnonRateThrottle class RegisterAnonThrottle(AnonRateThrottle): scope = 'register'
然后在settings.py配置限流规则:
REST_FRAMEWORK = { 'DEFAULT_THROTTLE_RATES': { 'register': '3/min', # 匿名用户每分钟最多3次注册请求 } }
最后把限流类加到UserViewSet的create动作上,同样支持环境开关:
def get_throttles(self): throttles = super().get_throttles() if self.action == 'create' and not settings.DEBUG: throttles.append(RegisterAnonThrottle()) return throttles
注意事项
- 该方案属于低成本防护,能挡住绝大多数无针对性的批量注册脚本,如果需要更高等级的防护,可以额外添加图形验证码、手机号/邮箱校验等逻辑
- 自定义请求头的密钥要定期更换,生产环境不要硬编码在代码库中
内容的提问来源于stack exchange,提问作者dabljues
相关产品推荐
相关产品推荐

