Programming

Django Rest Framework는 csrf를 제거합니다.

procodes 2020. 8. 27. 22:21
반응형

Django Rest Framework는 csrf를 제거합니다.


Django Rest Framework에 대한 답변이 있다는 것을 알고 있지만 내 문제에 대한 해결책을 찾을 수 없습니다.

인증 및 일부 기능이있는 응용 프로그램이 있습니다. Django Rest Framework를 사용하는 새 앱을 추가했습니다. 이 앱에서만 라이브러리를 사용하고 싶습니다. 또한 POST 요청을하고 싶습니다. 항상이 응답을받습니다.

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

다음 코드가 있습니다.

# 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})

현재 애플리케이션에 영향을주지 않고 API를 추가하고 싶습니다. 그래서 내 질문은 어떻게이 앱에 대해서만 CSRF를 비활성화 할 수 있습니까?


이 오류가 발생하는 이유는 무엇입니까?

이것은 SessionAuthenticationDRF에서 사용 하는 기본 체계 때문에 발생 합니다. DRF SessionAuthentication는 CSRF를 확인해야하는 인증을 위해 Django의 세션 프레임 워크를 사용합니다.

authentication_classes뷰 / 뷰셋에 아무것도 정의하지 않으면 DRF는이 인증 클래스를 기본값으로 사용합니다.

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

DRF는 동일한 뷰에 대한 세션 및 비 세션 기반 인증을 모두 지원해야하므로 인증 된 사용자에 대해서만 CSRF 검사를 시행합니다. 이는 인증 된 요청에만 CSRF 토큰이 필요하며 익명 요청은 CSRF 토큰없이 전송 될 수 있음을 의미합니다.

SessionAuthentication과 함께 AJAX 스타일 API를 사용하는 경우 PUT, PATCH, POST or DELETE요청 과 같은 "안전하지 않은"HTTP 메서드 호출에 대해 유효한 CSRF 토큰을 포함해야 합니다.

그러면 무엇을해야합니까?

이제 csrf 검사를 비활성화 CsrfExemptSessionAuthentication하려면 기본 SessionAuthentication클래스 에서 확장되는 사용자 지정 인증 클래스 만들 수 있습니다 . 이 인증 클래스에서는 enforce_csrf()실제 .NET 내부에서 발생한 검사를 재정의합니다 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

보기에서 다음과 같이 정의 할 수 authentication_classes있습니다.

authentication_classes = (CsrfExemptSessionAuthentication, BasicAuthentication)

이것은 csrf 오류를 처리해야합니다.


더 쉬운 솔루션 :

views.py에서 중괄호 CsrfExemptMixin 및 authentication_classes를 사용하십시오.

# 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})

urls.py 수정

urls.py에서 경로를 관리하는 경우 원하는 경로를 csrf_exempt ()로 래핑하여 CSRF 확인 미들웨어에서 제외 할 수 있습니다.

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())),
    ...
)

또는 데코레이터로서 일부는 @csrf_exempt 데코레이터를 자신의 요구에 더 적합하게 사용할 수 있습니다.

예를 들어

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

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

작업을 완료해야합니다!


If you do not want to use session based authentication, you can remove Session Authentication from REST_AUTHENTICATION_CLASSES and that would automatically remove all csrf based issues. But in that case Browseable apis might not work.

Besides this error should not come even with session authentication. You should use custom authentication like TokenAuthentication for your apis and make sure to send Accept:application/json and Content-Type:application/json(provided you are using json) in your requests along with authentication token.


For all who did not find a helpful answer. Yes DRF automatically removes CSRF protection if you do not use SessionAuthentication AUTHENTICATION CLASS, for example, many developers use only JWT:

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

But issue CSRF not set may be occurred from some another reason, for exmple you not correctly added path to you view:

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

instead of

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

I tried a few of the answers above and felt creating a separate class was a little overboard.

For reference, I ran into this problem when trying to update a function based view method to a class based view method for user registration.

When using class-based-views (CBVs) and Django Rest Framework (DRF), Inherit from the ApiView class and set permission_classes and authentication_classes to an empty tuple. Find an example below.

class UserRegistrationView(APIView):

    permission_classes = ()
    authentication_classes = ()

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

        # rest of your code here

I am struck with the same problem. I followed this reference and it worked. Solution is to create a middleware

Add disable.py file in one of your apps (in my case it is 'myapp')

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

And add the middileware to the MIDDLEWARE_CLASSES

MIDDLEWARE_CLASSES = (
myapp.disable.DisableCSRF,
)

If you are using an exclusive virtual environment for your application, you can use the following approach without effective any other applications.

What you observed happens because rest_framework/authentication.py has this code in the authenticate method of SessionAuthentication class:

self.enforce_csrf(request)

You can modify the Request class to have a property called csrf_exempt and initialize it inside your respective View class to True if you do not want CSRF checks. For example:

Next, modify the above code as follows:

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

There are some related changes you'd have to do it in the Request class. A complete implementation is available here (with full description): https://github.com/piaxis/django-rest-framework/commit/1bdb872bac5345202e2f58728d0e7fad70dfd7ed


My Solution is shown blow. Just decorate my class.

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

This could also be a problem during a DNS Rebinding attack.

In between DNS changes, this can also be a factor. Waiting till DNS is fully flushed will resolve this if it was working before DNS problems/changes.

참고URL : https://stackoverflow.com/questions/30871033/django-rest-framework-remove-csrf

반응형