Django Rest Framework csrf'yi kaldır


112

Django Rest Framework ile ilgili cevaplar olduğunu biliyorum, ancak sorunuma bir çözüm bulamadım.

Kimlik doğrulaması ve bazı işlevleri olan bir uygulamam var. Ona Django Rest Framework kullanan yeni bir uygulama ekledim. Kitaplığı yalnızca bu uygulamada kullanmak istiyorum. Ayrıca POST isteğinde bulunmak istiyorum ve her zaman şu yanıtı alıyorum:

{
    "detail": "CSRF Failed: CSRF token missing or incorrect."
}

Takip koduna sahibim:

# urls.py
from django.conf.urls import patterns, url


urlpatterns = patterns(
    'api.views',
    url(r'^object/$', views.Object.as_view()),
)

# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from django.views.decorators.csrf import csrf_exempt


class Object(APIView):

    @csrf_exempt
    def post(self, request, format=None):
        return Response({'received data': request.data})

Mevcut uygulamayı etkilemeden API eklemek istiyorum. Öyleyse sorularım, CSRF'yi yalnızca bu uygulama için nasıl devre dışı bırakabilirim?


Zaten @csrf_exempt token kullanıyorsunuz. Bunu tüm görünümde kullanabilirsiniz. Bu işe yaramaz mı?
mukesh

Hayır, hâlâ ayrıntıya sahibim: "CSRF Başarısız: CSRF simgesi eksik veya yanlış." İleti. Cevaplardan, varsayılan kimlik doğrulamasını kaldırmam gerektiği sonucuna vardım.
Irene Texas

1
Token kimlik doğrulamasını kullanarak ÇOK benzer bir durumla karşılaşıyordum. Aynı teknedeki diğer herkes için: stackoverflow.com/questions/34789301/…
The Brewmaster

Yanıtlar:


218

Bu hata neden oluyor?

Bu, SessionAuthenticationDRF tarafından kullanılan varsayılan şema nedeniyle oluyor . DRF'ler SessionAuthentication, CSRF'nin kontrol edilmesini gerektiren kimlik doğrulama için Django'nun oturum çerçevesini kullanır.

authentication_classesGörünüm / görünüm kümenizde herhangi bir tanımlamadığınız zaman , DRF bu kimlik doğrulama sınıflarını varsayılan olarak kullanır.

'DEFAULT_AUTHENTICATION_CLASSES'= (
    'rest_framework.authentication.SessionAuthentication',
    'rest_framework.authentication.BasicAuthentication'
),

DRF'nin aynı görünümler için hem oturum hem de oturum tabanlı olmayan kimlik doğrulamasını desteklemesi gerektiğinden, yalnızca kimliği doğrulanmış kullanıcılar için CSRF kontrolünü zorunlu kılar. Bu, yalnızca kimliği doğrulanmış isteklerin CSRF belirteçleri gerektirdiği ve anonim isteklerin CSRF belirteçleri olmadan gönderilebileceği anlamına gelir.

SessionAuthentication ile AJAX tarzı bir API kullanıyorsanız, PUT, PATCH, POST or DELETEistekler gibi "güvenli olmayan" HTTP yöntem çağrıları için geçerli bir CSRF belirteci eklemeniz gerekir .

O zaman ne yapmalı?

Şimdi csrf kontrolünü devre dışı bırakmak CsrfExemptSessionAuthenticationiçin, varsayılan SessionAuthenticationsınıftan genişleyen özel bir kimlik doğrulama sınıfı oluşturabilirsiniz . Bu kimlik doğrulama sınıfında, enforce_csrf()gerçek içinde gerçekleşen denetimi geçersiz kılacağız SessionAuthentication.

from rest_framework.authentication import SessionAuthentication, BasicAuthentication 

class CsrfExemptSessionAuthentication(SessionAuthentication):

    def enforce_csrf(self, request):
        return  # To not perform the csrf check previously happening

Sizin görüşünüzde, şu şekilde tanımlayabilirsiniz authentication_classes:

authentication_classes = (CsrfExemptSessionAuthentication, BasicAuthentication)

Bu, csrf hatasını ele almalıdır.


10
Üzgünüm belki noktayı kaçırdım, ancak csrf korumasını atlamak / devre dışı bırakmak için bir güvenlik riski değil mi?
Paolo

1
@Paolo OP'nin belirli bir API için CSRF kimlik doğrulamasını devre dışı bırakması gerekir. Ama evet, csrf korumasını devre dışı bırakmak bir güvenlik riski. Belirli bir kullanım durumu için oturum kimlik doğrulamasını devre dışı bırakmanız gerekirse, bu çözümü kullanabilir.
Rahul Gupta

Hey @RahulGupta - Görünümde csrf_exempt dekoratörünü kontrol etmenin ve daha sonra bu görünümler için yalnızca zorunlu_csrf'yi devre dışı bırakmanın bir yolu yok mu?
Abhishek

@Abhishek Belki aşağıda aradığınız ans bixente57 tarafından. Özel görünümler için csrf'yi devre dışı bırakır.
Rahul Gupta

1
@RahulGupta_csrf'yi zorlamak istemiyorsanız, o zaman en iyi yol nedir?
oyuncu

21

Daha kolay çözüm:

Views.py içinde, CsrfExemptMixin ve authentication_classes parantezlerini kullanın:

# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from django.views.decorators.csrf import csrf_exempt
from braces.views import CsrfExemptMixin


class Object(CsrfExemptMixin, APIView):
    authentication_classes = []

    def post(self, request, format=None):
        return Response({'received data': request.data})

1
Teşekkürler, sorun için en kolay çözüm budur. Oauth2_provider ve token kullanan API'm.
Dat TT

1
ahhhh adamım. CsrfExemptMixin vardı, ancak authentication_classes = [] yoktu. Teşekkür ederim!
MagicLAMP

Bilginize, kimlik doğrulama_ sınıfları satırı anahtar gibi görünüyor. CsrfExemptMixin ile veya olmadan benim için aynı şekilde çalışır.
Dashdrum

14

Urls.py'yi değiştirin

Rotalarınızı urls.py'de yönetiyorsanız, istediğiniz rotaları CSRF doğrulama ara yazılımından hariç tutmak için csrf_exempt () ile sarmalayabilirsiniz.

from django.conf.urls import patterns, url
    from django.views.decorators.csrf import csrf_exempt
    import views

urlpatterns = patterns('',
    url(r'^object/$', csrf_exempt(views.ObjectView.as_view())),
    ...
)

Alternatif olarak, bir Dekoratör olarak Bazıları @csrf_exempt dekoratörün kullanımını ihtiyaçları için daha uygun bulabilir.

Örneğin,

from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse

@csrf_exempt
def my_view(request):
    return HttpResponse('Hello world')

İş Bitti'yi almalısınız!


Koda bazı açıklamalar daha iyi bir cevap verebilir.
chevybow

@chevybow Gerçekten Üzgünüm, aslında Toplulukta Yeniyim. Aslında, Belirli Bir Görünüm için CSRF'yi devre dışı bırakan bir Django Dekoratörü
Syed Faizan

bu benim için python3 ve django 1.11 ile çalıştı ve en kolay görünüyor!
madannes

12

Yararlı bir cevap bulamayanlar için. Evet DRF SessionAuthentication, KİMLİK DOĞRULAMA SINIFI kullanmıyorsanız CSRF korumasını otomatik olarak kaldırır , örneğin, birçok geliştirici yalnızca JWT kullanır:

'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
    ),

Ancak sorun CSRF not setbaşka bir nedenden kaynaklanıyor olabilir, örneğin, görüntünüze doğru yolu eklememişsinizdir:

url(r'^api/signup/', CreateUserView),  # <= error! DRF cant remove CSRF because it is not as_view that does it!

onun yerine

url(r'^api/signup/', CreateUserView.as_view()),

8

Yukarıdaki cevaplardan birkaçını denedim ve ayrı bir sınıf oluşturmanın biraz abartılı olduğunu hissettim.

Referans olarak, işlev tabanlı bir görünüm yöntemini kullanıcı kaydı için sınıf tabanlı bir görünüm yöntemine güncellemeye çalışırken bu sorunla karşılaştım.

Sınıf tabanlı görünümleri (CBV'ler) ve Django Rest Çerçevesini (DRF) kullanırken, ApiView sınıfından devralın ve izin_ sınıfları ile kimlik doğrulama_ sınıflarını boş bir demete ayarlayın. Aşağıda bir örnek bulun.

class UserRegistrationView(APIView):

    permission_classes = ()
    authentication_classes = ()

    def post(self, request, *args, **kwargs):

        # rest of your code here

7

Oturum tabanlı kimlik doğrulamasını kullanmak istemiyorsanız Session Authentication, REST_AUTHENTICATION_CLASSES öğesinden kaldırabilirsiniz ve bu, tüm csrf tabanlı sorunları otomatik olarak kaldırır. Ancak bu durumda, Browseable api'ler çalışmayabilir.

Ayrıca bu hata oturum kimlik doğrulamasında bile gelmemelidir. API'leriniz için TokenAuthentication gibi özel kimlik doğrulaması kullanmalı ve kimlik doğrulama belirteci ile birlikte isteklerinizde Accept:application/jsonve Content-Type:application/json(json kullanıyorsanız) gönderdiğinizden emin olmalısınız .


4

Varsayılan oturum kimlik doğrulamasını önlemek için bunu eklemeniz gerekir: (settings.py)

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated', 
    )
}

Ardından: (views.py)

from rest_framework.permissions import AllowAny

class Abc(APIView):
    permission_classes = (AllowAny,)

    def ...():

3

Ben de aynı sorunla karşılaştım. Bu referansı takip ettim ve işe yaradı. Çözüm, bir ara yazılım oluşturmaktır

Uygulamalarınızdan birine disable.py dosyası ekleyin (benim durumumda bu 'uygulamam')

class DisableCSRF(object):
    def process_request(self, request):
        setattr(request, '_dont_enforce_csrf_checks', True)

Middileware'i MIDDLEWARE_CLASSES'e ekleyin

MIDDLEWARE_CLASSES = (
myapp.disable.DisableCSRF,
)

4
Bu, web sitenizin tamamını CSRF saldırılarına açık hale getirecektir. en.wikipedia.org/wiki/Cross-site_request_forgery
Jeanno

1

Uygulamanız için özel bir sanal ortam kullanıyorsanız, aşağıdaki yaklaşımı başka hiçbir uygulamada etkili olmadan kullanabilirsiniz.

Gözlemlediğiniz şey , sınıf yönteminde rest_framework/authentication.pybu koda sahip olduğu için olur :authenticateSessionAuthentication

self.enforce_csrf(request)

CSRF kontrollerini istemiyorsanız , Requestsınıfı bir özelliğe sahip olacak şekilde değiştirebilir ve csrf_exemptilgili View sınıfınız içinde başlatabilirsiniz True. Örneğin:

Ardından, yukarıdaki kodu aşağıdaki gibi değiştirin:

if not request.csrf_exempt:
    self.enforce_csrf(request)

RequestSınıfta yapmanız gereken bazı ilgili değişiklikler var . Tam bir uygulama burada (tam açıklama ile) mevcuttur: https://github.com/piaxis/django-rest-framework/commit/1bdb872bac5345202e2f58728d0e7fad70dfd7ed


1

Çözümüm darbe gösteriliyor. Sadece sınıfımı dekore et.

from django.views.decorators.csrf import csrf_exempt
@method_decorator(csrf_exempt, name='dispatch')
@method_decorator(basic_auth_required(
    target_test=lambda request: not request.user.is_authenticated
), name='dispatch')
class GenPedigreeView(View):
    pass

1
Bu kod soruyu yanıtlayabilirken, bu kodun soruyu neden ve / veya nasıl yanıtladığına ilişkin ek bağlam sağlamak, uzun vadeli değerini artırır.
Alex Riabov

1

REST API POST'larını kullanırken, X-CSRFToken istek başlığının olmaması bu hataya neden olabilir. Django belgeleri , JS'den CSRF belirteç değerini alma ve ayarlama konusunda örnek bir kod sağlar.

Yukarıdaki yanıtlarda belirtildiği gibi, CSRF kontrolü SessionAuthentication kullanıldığında gerçekleşir. Diğer bir yaklaşım TokenAuthentication kullanmaktır, ancak REST_FRAMEWORK ayarının DEFAULT_AUTHENTICATION_CLASSES listesinde ilk sıraya yerleştirilmesi gerektiğini unutmayın.


-1

Bu, DNS Yeniden Bağlama saldırısı sırasında da bir sorun olabilir .

DNS değişiklikleri arasında bu da bir faktör olabilir. DNS'nin tamamen temizlenmesini beklemek, DNS sorunları / değişikliklerinden önce çalışıyorsa sorunu çözecektir.


Bunun yukarıdaki soruyla ne ilgisi var?
boatcoder

Bu sorunun, DNS'yi değiştirirken ortaya çıkabileceği ve tam olarak yayılmadığı anlamına gelir. Uygulamanın Django normal oturumundan farklı bir yönlendirmesi varsa, nedeni budur. Sadece karşılaştığım uç vakadan haber veriyorum. Bu biraz kanonik bir kaynak gibi görünüyor, bu yüzden ek bir kaynak ekleyeceğimi düşündüm.
chris Frisina
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.