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

基于Django REST Framework的安全联系表单实现方案咨询

Securing Your Django REST Framework Contact Form Endpoint Against Spam

Great question—protecting public contact form APIs from spam bots is a common pain point, and you’re absolutely right that client-side captchas alone aren’t enough. Bots can easily scrape your API endpoint from JS and hit it directly, so you need layered, server-first defenses. Here’s how to harden your website/contact endpoint:

1. Enforce Server-Side Rate Limiting

DRF has built-in throttling that lets you restrict how often anonymous users can hit your endpoint. This stops bots from flooding your API with requests.

  • Configure a global throttle in your settings.py:
    REST_FRAMEWORK = {
        'DEFAULT_THROTTLE_CLASSES': [
            'rest_framework.throttling.AnonRateThrottle',
        ],
        'DEFAULT_THROTTLE_RATES': {
            'anon': '5/minute',  # Adjust based on your typical user behavior
        }
    }
    
  • Or apply it only to your contact view for targeted control:
    from rest_framework.throttling import AnonRateThrottle
    from rest_framework.views import APIView
    
    class ContactView(APIView):
        throttle_classes = [AnonRateThrottle]
        # ... your POST logic here
    

For extra strictness, you can build a custom throttle that tracks IP addresses more granularly, or limits requests per session if users are logged in.

2. Add a Honeypot Field

Bots love filling out every input field they see—use that against them. Add a hidden field to your form that normal users won’t interact with, then reject any request where this field has a value.

In your DRF serializer:

from rest_framework import serializers

class ContactSerializer(serializers.Serializer):
    name = serializers.CharField()
    email = serializers.EmailField()
    message = serializers.CharField()
    # Honeypot field—hidden with CSS on the frontend
    honeypot = serializers.CharField(required=False, write_only=True)

    def validate(self, data):
        if data.get('honeypot'):
            raise serializers.ValidationError("Invalid submission")
        return data

On the frontend, hide the field with CSS: #id_honeypot { display: none; }—most bots won’t check for this simple trick.

3. Implement Time-Based Validation

Humans take at least a few seconds to fill out a contact form. Reject submissions that happen too quickly (e.g., less than 3 seconds after the page loads).

  • On the frontend, record the timestamp when the page loads, then send it with the form data:
    const pageLoadTime = Date.now();
    // Include pageLoadTime in your POST request body
    
  • In your DRF view, calculate the time difference and reject if it’s too short:
    import time
    from rest_framework import status
    from rest_framework.response import Response
    
    def post(self, request):
        submit_time = int(time.time() * 1000)
        load_time = request.data.get('page_load_time')
        if load_time and (submit_time - int(load_time)) < 3000:  # Less than 3 seconds
            return Response({"error": "Submission too fast"}, status=status.HTTP_400_BAD_REQUEST)
        # ... rest of your form processing logic
    

You can also tie this to a CSRF token: generate a token with a timestamp server-side, then validate the elapsed time when the token is submitted.

4. Enforce CSRF Protection

Even for anonymous endpoints, CSRF protection can block bots that don’t properly handle cookies. DRF enables this by default for views using session authentication, but for anonymous users, you’ll need to ensure the frontend sends the CSRF token.

  • On the frontend, fetch the CSRF token from the csrftoken cookie and include it in the request headers:
    const csrftoken = document.cookie.split('; ').find(row => row.startsWith('csrftoken=')).split('=')[1];
    fetch('/website/contact', {
        method: 'POST',
        headers: {
            'X-CSRFToken': csrftoken,
            'Content-Type': 'application/json',
        },
        // ... body data
    });
    
  • In your Django settings, make sure django.middleware.csrf.CsrfViewMiddleware is enabled (it should be by default).

5. Content-Based Spam Filtering

Use a service like Akismet to check if the submitted message is spam. It’s easy to integrate with Django:

  1. Install django-akismet: pip install django-akismet
  2. Add your Akismet API key to settings.py:
    AKISMET_API_KEY = 'your-api-key'
    AKISMET_BLOG_URL = 'https://yourwebsite.com'
    
  3. In your view, check the submission before sending the email:
    from akismet import Akismet
    from rest_framework import status
    from rest_framework.response import Response
    
    def post(self, request):
        akismet = Akismet(
            api_key=settings.AKISMET_API_KEY,
            blog_url=settings.AKISMET_BLOG_URL
        )
        is_spam = akismet.check_comment(
            user_ip=request.META.get('REMOTE_ADDR'),
            user_agent=request.META.get('HTTP_USER_AGENT'),
            comment_content=request.data.get('message'),
            comment_author=request.data.get('name'),
            comment_author_email=request.data.get('email')
        )
        if is_spam:
            return Response({"error": "Spam detected"}, status=status.HTTP_400_BAD_REQUEST)
        # ... send email to admin logic
    

You can also add simple keyword filtering for obvious spam terms, but services like Akismet are far more effective at catching sophisticated spam.

6. Validate Request Metadata

Add lightweight checks to reject obvious bot requests:

  • User-Agent Filtering: Reject requests with missing or suspicious User-Agents (e.g., empty strings, bot-specific UAs like "Googlebot" if you don’t want crawlers hitting the endpoint).
  • Referer Check: Ensure the request comes from your own domain (note: Referer can be spoofed, so this is just an extra layer, not a primary defense).

Example in your view:

def post(self, request):
    referer = request.META.get('HTTP_REFERER')
    if referer and not referer.startswith('https://yourwebsite.com'):
        return Response({"error": "Invalid referer"}, status=status.HTTP_400_BAD_REQUEST)
    
    user_agent = request.META.get('HTTP_USER_AGENT')
    if not user_agent or 'bot' in user_agent.lower():
        return Response({"error": "Invalid user agent"}, status=status.HTTP_400_BAD_REQUEST)
    # ... rest of logic

7. Server-Side Captcha Validation

If you do use a captcha (like reCAPTCHA), never rely only on frontend validation. Always verify the captcha response on the server.

For reCAPTCHA v2/v3:

  1. Install django-recaptcha: pip install django-recaptcha
  2. Add your keys to settings.py:
    RECAPTCHA_PUBLIC_KEY = 'your-public-key'
    RECAPTCHA_PRIVATE_KEY = 'your-private-key'
    
  3. Add the captcha field to your serializer:
    from captcha.fields import ReCaptchaField
    from rest_framework import serializers
    
    class ContactSerializer(serializers.Serializer):
        # ... other fields
        captcha = ReCaptchaField()
    

DRF will automatically validate the captcha response with Google’s server before processing the request.


Final Notes

The key is to use layered defenses—no single method will stop all spam, but combining rate limiting, honeypots, time checks, and content filtering will make it much harder for bots to abuse your endpoint. Start with the simplest methods (rate limiting, honeypot) then add more as needed based on the spam you encounter.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 08:31:05