You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django Rest Framework如何限制未认证用户非法访问公开API

DRF联系表单API安全修复方案

核心问题梳理

你当前的接口存在两个高危问题:

  • 匿名用户可直接通过GET请求拉取所有用户提交的联系表单数据,属于严重的数据泄露
  • 接口无来源校验,任何工具、站点都可以随意构造POST请求提交垃圾数据
  • 仅靠频率限制无法拦截低频次的恶意请求,必须配合来源、合法性校验

修复步骤

1. 第一优先级:关闭公开的GET数据接口

匿名用户完全没有获取所有联系表单数据的需求,不要把数据查询和表单提交写在同一个接口里:

  1. 把提交接口的允许方法仅保留POST
  2. 如果确实需要后台查看提交数据,单独开一个仅管理员可访问的GET接口
    修改后的视图代码:
from django.conf import settings
from django.http import HttpResponseForbidden
from django.views.decorators.csrf import csrf_protect
from rest_framework import status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAdminUser, AllowAny
from .serializers import ContactSerializer
from .models import Contact


@api_view(['POST'])
@permission_classes([AllowAny])
@csrf_protect
def farhyn_api(request):
    # 先校验请求来源
    origin = request.META.get('HTTP_ORIGIN', '')
    referer = request.META.get('HTTP_REFERER', '')
    allowed_domains = settings.ALLOWED_FRONTEND_ORIGINS
    source_valid = any(origin.startswith(domain) or referer.startswith(domain) for domain in allowed_domains)
    if not source_valid:
        return HttpResponseForbidden("非法请求来源")

    # 表单提交逻辑
    serializer = ContactSerializer(data=request.data)
    if serializer.is_valid():
        serializer.save()
        return Response(
            {'status': True, 'message': 'success'},
            status=status.HTTP_201_CREATED
        )
    return Response(
        {'status': False, 'message': serializer.errors},
        status=status.HTTP_400_BAD_REQUEST
    )


# 仅管理员可访问的列表接口
@api_view(['GET'])
@permission_classes([IsAdminUser])
def contact_list_admin(request):
    contact = Contact.objects.all()
    serializer = ContactSerializer(contact, many=True)
    return Response(serializer.data)

注意:原代码里返回的sucess是拼写错误,正确拼写为success

2. 配置允许的前端域名

在settings.py里添加你自己的前端域名白名单,同时保留原有的限流配置:

# 新增前端域名白名单
ALLOWED_FRONTEND_ORIGINS = [
    "https://你的正式站点域名",
    "http://localhost:5173", # 本地开发用的前端地址,上线后可删除
]

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
    ],
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle',
    ],
    'DEFAULT_THROTTLE_RATES': {
        'anon': '10/minute',
    }
}

同时记得在Django的CORS_ALLOWED_ORIGINS配置里也加上上述白名单域名,不要开CORS_ALLOW_ALL_ORIGINS。

3. 前端配合携带CSRF令牌

Django的CSRF校验会拦截没有合法令牌的伪造请求,React侧只需要在提交请求时从cookie读取csrftoken,放到请求头X-CSRFToken中即可,以axios为例:

import axios from 'axios'

// 从cookie读取csrftoken的工具方法
const getCookie = (name) => {
  let value = "; " + document.cookie;
  let parts = value.split("; " + name + "=");
  if (parts.length === 2) return parts.pop().split(";").shift();
}

// 全局配置axios
axios.defaults.withCredentials = true
axios.defaults.headers.post['X-CSRFToken'] = getCookie('csrftoken')

补充说明

没有任何方案能100%阻止专业人员用工具伪造请求——所有前端能携带的参数、请求头都可以被模拟。但上述配置做完后:

  • 用户直接在浏览器输入API地址,会因为方法不被允许返回405,看不到任何数据
  • 用Postman等工具直接构造请求,会因为来源不合法、没有正确CSRF令牌被直接拦截,返回403
  • 批量刷接口的行为会被你之前配置的频率限制拦住
    如果还遇到垃圾提交,可以再加一层图形验证码、人机验证,拦截率会更高。

内容的提问来源于stack exchange,提问作者hawaj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 21:09:58