Django CSRF Token Hatası (403 Forbidden) Nasıl Çözülür? 5 Kesin Çözüm (2026)

01.01.2026 20:35 Haber

Web geliştiricilerin sıkça karşılaştığı Django CSRF Token Hatası (CSRF Token Missing Error), form gönderimlerinde güvenlik katmanı olan Cross-Site Request Forgery korumasından kaynaklanır. Alesta Web olarak bu hatanın nedenlerini, çözümlerini ve Django güvenlik best practices'i detaylı şekilde anlatalım.

CSRF Nedir ve Neden Önemlidir?

Cross-Site Request Forgery (CSRF), kötü niyetli sitelerin kullanıcı adına yetkisiz işlemler yapmasını engelleyen bir güvenlik mekanizmasıdır. Django framework'ü varsayılan olarak tüm POST isteklerinde CSRF Token kontrolü yapar.

? CSRF Koruması Nasıl Çalışır?

Adım Açıklama
1. Token Oluşturma Django her session için benzersiz token üretir
2. Template'e Gömme {% csrf_token %} tag ile form'a hidden input eklenir
3. Cookie Gönderme csrftoken cookie'si tarayıcıya kaydedilir
4. Doğrulama POST isteğinde token ile cookie eşleştirilir
? İstatistik:

OWASP 2025 raporuna göre CSRF saldırıları web uygulamalarındaki güvenlik açıklarının %8'ini oluşturuyor. Django'nun otomatik CSRF koruması bu riski minimize eder.

Django CSRF Token Hatası Nedenleri

Django CSRF Token Hatası genellikle şu senaryolarda ortaya çıkar:

❌ Yaygın Hata Mesajları

# Hata 1: Template'de token eksik
Forbidden (403)
CSRF verification failed. Request aborted.
Reason given for failure:
    CSRF token missing or incorrect.

# Hata 2: AJAX'ta header eksik
403 Forbidden - CSRF token missing

# Hata 3: Middleware devre dışı
ImproperlyConfigured: CSRF middleware not installed

Alesta Web müşterilerimizin %30'u Django projelerinde bu hatayla karşılaşıyor. En yaygın nedenler:

  • Form template'inde {% csrf_token %} tag'inin unutulması
  • AJAX isteklerinde X-CSRFToken header'ının eksik olması
  • CSRF Middleware'inin INSTALLED_APPS'ten silinmesi
  • Cookie SameSite ayarlarının yanlış yapılandırılması
  • HTTPS/HTTP karışık kullanımı (mixed content)

Çözüm 1: {% csrf_token %} Template Tag Ekleme

En yaygın Django CSRF Token Hatası çözümü, form template'ine doğru tag'i eklemektir:

❌ Yanlış Kullanım (Token Yok)

<!-- templates/contact.html -->
<form method="post" action="/contact/">
    <input type="text" name="name" placeholder="Adınız">
    <input type="email" name="email" placeholder="Email">
    <button type="submit">Gönder</button>
</form>

✅ Doğru Kullanım (Token Eklendi)

<!-- templates/contact.html -->
<form method="post" action="/contact/">
    {% csrf_token %}
    <input type="text" name="name" placeholder="Adınız">
    <input type="email" name="email" placeholder="Email">
    <button type="submit">Gönder</button>
</form>
✅ Sonuç:

Django otomatik olarak şu HTML'i oluşturur:

<input type="hidden" name="csrfmiddlewaretoken"
       value="xK3l9mP2...64karakterlik_token">
⚠️ Dikkat:

{% csrf_token %} tag'i mutlaka <form> tag'lerinin içinde olmalıdır. Dışarıda kullanırsanız token oluşturulur ama form ile gönderilmez.

Çözüm 2: AJAX İsteklerinde X-CSRFToken Header

JavaScript ile AJAX kullanıyorsanız, CSRF Token Missing hatası almamak için HTTP header'a token eklemelisiniz:

JavaScript Fetch API ile CSRF

// Cookie'den CSRF token'ı al
function getCookie(name) {
    let cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        const cookies = document.cookie.split(';');
        for (let i = 0; i < cookies.length; i++) {
            const cookie = cookies[i].trim();
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

const csrftoken = getCookie('csrftoken');

// Fetch ile POST isteği
fetch('/api/submit/', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'X-CSRFToken': csrftoken
    },
    body: JSON.stringify({ name: 'Test', email: 'test@example.com' })
})
.then(response => response.json())
.then(data => console.log('Başarılı:', data))
.catch(error => console.error('Hata:', error));

jQuery AJAX ile CSRF

// jQuery ile CSRF token ayarlama
function csrfSafeMethod(method) {
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
        }
    }
});

// Artık tüm AJAX istekleri otomatik token gönderir
$.post('/api/submit/', {
    name: 'Test',
    email: 'test@example.com'
}, function(data) {
    console.log('Başarılı:', data);
});

Alesta Web projelerinde React ve Vue.js kullanıyorsak, axios interceptor ile global CSRF token ayarı yapıyoruz:

Axios ile Global CSRF Ayarı

// axios-config.js
import axios from 'axios';

// CSRF token'ı cookie'den al
const csrftoken = document.cookie
    .split('; ')
    .find(row => row.startsWith('csrftoken='))
    ?.split('=')[1];

// Tüm isteklere otomatik ekle
axios.defaults.headers.common['X-CSRFToken'] = csrftoken;
axios.defaults.withCredentials = true;

export default axios;

Çözüm 3: CSRF Exempt Decorator Kullanımı

API endpoint'leri veya webhook'lar için Django CSRF Token Hatası kontrolünü devre dışı bırakabilirsiniz (dikkatli kullanın):

@csrf_exempt Decorator

# views.py
from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse
import json

@csrf_exempt
def webhook_endpoint(request):
    """
    Dış servislerden gelen webhook'lar için CSRF kontrolü devre dışı
    ÖNEMLİ: Sadece güvenli authentication mekanizması olan endpoint'lerde kullanın
    """
    if request.method == 'POST':
        try:
            data = json.loads(request.body)
            # Webhook işleme mantığı
            return JsonResponse({'status': 'success', 'message': 'Webhook alındı'})
        except json.JSONDecodeError:
            return JsonResponse({'status': 'error', 'message': 'Geçersiz JSON'}, status=400)
    return JsonResponse({'status': 'error', 'message': 'Sadece POST'}, status=405)

Class-Based View'de CSRF Exempt

# views.py
from django.views import View
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt

@method_decorator(csrf_exempt, name='dispatch')
class StripeWebhookView(View):
    """
    Stripe webhook'ları için CSRF bypass
    Stripe signature doğrulaması yapıyor, CSRF'ye gerek yok
    """
    def post(self, request):
        payload = request.body
        sig_header = request.META['HTTP_STRIPE_SIGNATURE']

        # Stripe signature doğrulama
        # ... (webhook işleme kodu)

        return JsonResponse({'status': 'success'})
⚠️ GÜVENLİK UYARISI:

@csrf_exempt kullandığınızda CSRF koruması tamamen kalkar. Mutlaka alternatif güvenlik mekanizmaları kullanın:

  • API Key Authentication: Header'da secret key kontrolü
  • Signature Verification: Webhook signature doğrulama (Stripe, GitHub)
  • IP Whitelist: Sadece belirli IP'lerden kabul etme
  • Token-Based Auth: JWT veya OAuth 2.0

Çözüm 4: CSRF Middleware Kontrolü

CSRF Token Missing hatası alıyorsanız, middleware ayarlarınızı kontrol edin:

settings.py Doğru Yapılandırma

# settings.py
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',  # ✅ MUTLAKA OLMALI
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

# CSRF Cookie Ayarları
CSRF_COOKIE_SECURE = True  # Production'da HTTPS için
CSRF_COOKIE_HTTPONLY = False  # JavaScript'in cookie'ye erişmesi için False
CSRF_COOKIE_SAMESITE = 'Lax'  # Veya 'Strict' (third-party cookie engeller)
CSRF_TRUSTED_ORIGINS = [
    'https://yourdomain.com',
    'https://www.yourdomain.com',
]
✅ Middleware Doğrulama Komutu:
# Django shell'de middleware kontrolü
python manage.py shell

>>> from django.conf import settings
>>> 'django.middleware.csrf.CsrfViewMiddleware' in settings.MIDDLEWARE
True  # ✅ Bu True olmalı

Çözüm 5: Cookie SameSite Ayarları

Modern tarayıcılar (Chrome 80+, Firefox 69+) SameSite cookie politikası nedeniyle Django CSRF Token Hatası verebilir:

SameSite Ayarları Tablosu

Ayar Davranış Kullanım Durumu
Strict Cookie sadece same-site isteklerde gönderilir Maksimum güvenlik, tek domain
Lax Top-level navigation'da (link tıklama) gönderilir Önerilen (Django default)
None Tüm cross-site isteklerde gönderilir HTTPS + third-party iframes

Production Ayarları (settings.py)

# settings.py - Production ortamı için
import os

# CSRF Ayarları
CSRF_COOKIE_SECURE = True  # HTTPS zorunlu
CSRF_COOKIE_SAMESITE = 'Lax'  # Çoğu use case için yeterli
CSRF_USE_SESSIONS = False  # Cookie kullan (default)

# Session Ayarları
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_SAMESITE = 'Lax'

# Güvenilen domainler
CSRF_TRUSTED_ORIGINS = [
    'https://alestaweb.com',
    'https://www.alestaweb.com',
    'https://api.alestaweb.com',
]

# HTTPS redirect
SECURE_SSL_REDIRECT = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
? Alesta Web İpucu:

Subdomain'ler arasında CSRF token paylaşımı yapıyorsanız (örn: app.alestaweb.com → api.alestaweb.com), CSRF_COOKIE_DOMAIN ayarını kullanın:

CSRF_COOKIE_DOMAIN = '.alestaweb.com'  # Tüm subdomain'lerde geçerli

Production İpuçları

Alesta Web olarak production ortamlarında Django CSRF Token Hatası önlemek için şu pratikleri uyguluyoruz:

1️⃣ Nginx Reverse Proxy Ayarları

# /etc/nginx/sites-available/django-app
server {
    listen 443 ssl http2;
    server_name alestaweb.com;

    # SSL Sertifikaları
    ssl_certificate /etc/letsencrypt/live/alestaweb.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/alestaweb.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;  # ✅ HTTPS için önemli

        # CSRF cookie'lerinin düzgün iletilmesi
        proxy_cookie_path / "/; Secure; HttpOnly; SameSite=Lax";
    }
}

2️⃣ Docker Compose ile CSRF Ayarları

# docker-compose.yml
version: '3.8'

services:
  web:
    build: .
    command: gunicorn config.wsgi:application --bind 0.0.0.0:8000
    volumes:
      - .:/app
    environment:
      - DJANGO_SETTINGS_MODULE=config.settings.production
      - CSRF_COOKIE_SECURE=True
      - SESSION_COOKIE_SECURE=True
      - CSRF_TRUSTED_ORIGINS=https://alestaweb.com,https://www.alestaweb.com
    ports:
      - "8000:8000"
    depends_on:
      - db

  db:
    image: postgres:15
    environment:
      - POSTGRES_DB=django_db
      - POSTGRES_USER=django_user
      - POSTGRES_PASSWORD=secure_password

3️⃣ Logging ve Monitoring

# settings.py - CSRF hatalarını loglama
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'file': {
            'level': 'WARNING',
            'class': 'logging.FileHandler',
            'filename': '/var/log/django/csrf_errors.log',
        },
    },
    'loggers': {
        'django.security.csrf': {
            'handlers': ['file'],
            'level': 'WARNING',
            'propagate': False,
        },
    },
}

Güvenlik Best Practices

CSRF Token Missing hatasını çözerken güvenliği asla ihmal etmeyin:

✅ Yapılması Gerekenler

  • Her form'da {% csrf_token %}: Template'lerde asla unutmayın
  • AJAX'ta X-CSRFToken header: JavaScript isteklerinde mutlaka ekleyin
  • HTTPS kullanın: Production'da CSRF_COOKIE_SECURE=True
  • Trusted origins: CSRF_TRUSTED_ORIGINS listesini güncel tutun
  • SameSite=Lax: Modern tarayıcı uyumluluğu için

❌ Yapılmaması Gerekenler

  • @csrf_exempt aşırı kullanmak: Sadece API endpoint'lerinde, alternatif auth ile
  • CSRF middleware silmek: MIDDLEWARE'den asla çıkarmayın
  • HTTP'de SECURE=True: Development'ta False, production'da True olmalı
  • Wildcard origins: CSRF_TRUSTED_ORIGINS=['*'] güvenlik açığıdır
  • HttpOnly=True (CSRF için): JavaScript erişemez, AJAX çalışmaz
⚠️ Sık Yapılan Hatalar:

Alesta Web support ekibimizin gözlemlediği en yaygın hatalar:

  1. Mixed Content: HTTPS site'ta HTTP iframe/AJAX kullanımı
  2. Cookie Domain Mismatch: subdomain.example.com → example.com arası CSRF
  3. Cache Problemi: Nginx/Cloudflare cache'i CSRF token'ları cached ediyor
  4. CORS + CSRF: CORS izni var ama CSRF token gönderilmiyor
  5. Token Rotation: Long-lived session'larda token rotate etmiyor

✅ Özet: Django CSRF Token Hatası Çözüldü

Django CSRF Token Hatası genellikle template'e {% csrf_token %} eklenmemesi veya AJAX'ta X-CSRFToken header eksikliğinden kaynaklanır. CSRF Token Missing sorununu çözerken güvenliği ihmal etmeyin.

Hızlı Kontrol Listesi:

  • ✅ Form template'lerinde {% csrf_token %} tag'i var mı?
  • ✅ AJAX isteklerinde X-CSRFToken header gönderiliyor mu?
  • ✅ MIDDLEWARE listesinde CsrfViewMiddleware aktif mi?
  • ✅ Production'da CSRF_COOKIE_SECURE=True ayarlı mı?
  • ✅ CSRF_TRUSTED_ORIGINS doğru domain'leri içeriyor mu?
  • ✅ SameSite cookie ayarları modern tarayıcılara uygun mu?

Faydalı Kaynaklar:

© 2026 Alesta Web - Django güvenlik ve performans uzmanınız. Tüm hakları saklıdır.

WM Tools
💫

WebMaster Tools

15 Profesyonel Araç