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


111

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를 비활성화 할 수 있습니까?


이미 @csrf_exempt 토큰을 사용하고 있습니다. 전체보기에서 사용할 수 있습니다. 작동하지 않습니까?
mukesh

아니요, "CSRF 실패 : CSRF 토큰이 없거나 잘못되었습니다."라는 세부 정보가 계속 표시됩니다. 메시지. 기본 인증을 제거해야한다는 답변을 통해 결론을 내 렸습니다.
Irene Texas

1
토큰 인증을 사용하여 매우 유사한 상황에 처했습니다. : 같은 배에서 다른 사람을 위해 stackoverflow.com/questions/34789301/...
브루 마스터

답변:


218

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

이것은 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 오류를 처리해야합니다.


10
미안하지만 요점을 놓쳤을 수도 있지만 csrf 보호를 우회 / 비활성화하는 보안 위험은 없습니까?
Paolo

1
@Paolo OP는 특정 API에 대한 CSRF 인증을 비활성화하는 데 필요했습니다. 그러나 예, csrf 보호를 비활성화하는 것은 보안 위험입니다. 특정 사용 사례에 대해 세션 인증을 비활성화해야하는 경우이 솔루션을 사용할 수 있습니다.
Rahul Gupta

안녕하세요 @RahulGupta-뷰에서 csrf_exempt 데코레이터를 확인한 다음 해당 뷰에 대해서만 forced_csrf를 비활성화 할 방법이 없습니까?
Abhishek

@Abhishek 아마도 당신은 bixente57의 아래 ans 를 찾고 있습니다. 사용자 정의보기에 대해 csrf를 비활성화합니다.
Rahul Gupta

1
강요하고 싶지 않다면 @RahulGupta, 그러면 최선의 방법은 무엇입니까?
게이머

21

더 쉬운 솔루션 :

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

1
감사합니다. 이것이 문제에 대한 가장 쉬운 해결책입니다. oauth2_provider 및 토큰을 사용하는 내 API.
날엔 TT

1
아 남자. CsrfExemptMixin이 있었지만 authentication_classes = []가 없었습니다. 감사합니다!
MagicLAMP

참고로 authentication_classes 줄이 키인 것 같습니다. CsrfExemptMixin의 유무에 관계없이 동일하게 작동합니다.
Dashdrum

14

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')

작업을 완료해야합니다!


코드에 대한 설명이 더 나은 답변이 될 것입니다.
chevybow

@chevybow 정말 죄송합니다. 저는 실제로 커뮤니티가 처음입니다. 실제로 장고의 데코레이터로 특정 뷰에 대한 CSRF 비활성화
Syed Faizan

이것은 python3 및 django 1.11에서 나를 위해 일했으며 가장 쉬운 것 같습니다!
madannes

12

도움이되는 답을 찾지 못한 모든 사람들을 위해. 예 DRF는 SessionAuthenticationAUTHENTICATION CLASS를 사용하지 않는 경우 CSRF 보호를 자동으로 제거합니다. 예 를 들어 많은 개발자가 JWT 만 사용합니다.

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

그러나 CSRF not set다른 이유로 인해 문제 가 발생할 수 있습니다. 예를 들어보기에 경로를 올바르게 추가하지 않았기 때문입니다.

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

대신에

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

8

위의 답변 중 몇 가지를 시도해 보았고 별도의 수업을 만드는 것이 다소 과도하다고 느꼈습니다.

참고로 사용자 등록을 위해 함수 기반 뷰 메서드를 클래스 기반 뷰 메서드로 업데이트하려고 할 때이 문제가 발생했습니다.

CBV (클래스 기반 뷰) 및 DRF (Django Rest Framework)를 사용하는 경우 ApiView 클래스에서 상속하고 permission_classes 및 authentication_classes를 빈 튜플로 설정합니다. 아래에서 예를 찾으십시오.

class UserRegistrationView(APIView):

    permission_classes = ()
    authentication_classes = ()

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

        # rest of your code here

7

세션 기반 인증을 사용하지 않으려는 경우 Session AuthenticationREST_AUTHENTICATION_CLASSES에서 제거하면 모든 csrf 기반 문제가 자동으로 제거됩니다. 그러나이 경우 Browseable api가 작동하지 않을 수 있습니다.

게다가이 오류는 세션 인증에서도 오지 않아야합니다. API에 TokenAuthentication과 같은 사용자 지정 인증을 사용해야 하며 인증 토큰과 함께 요청에 Accept:application/jsonContent-Type:application/json(json을 사용 하는 경우) 전송 해야합니다.


4

기본 세션 인증을 방지하려면 다음을 추가해야합니다. (settings.py)

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

그런 다음 : (views.py)

from rest_framework.permissions import AllowAny

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

    def ...():

3

나는 같은 문제에 부딪쳤다. 이 참조를 따랐고 작동했습니다. 해결책은 미들웨어를 만드는 것입니다.

앱 중 하나에 disable.py 파일을 추가합니다 (제 경우에는 'myapp').

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

그리고 MIDDLEWARE_CLASSES에 미들웨어를 추가합니다.

MIDDLEWARE_CLASSES = (
myapp.disable.DisableCSRF,
)

4
이렇게하면 전체 웹 사이트가 CSRF 공격을 받기 쉽습니다. en.wikipedia.org/wiki/Cross-site_request_forgery
Jeanno

1

응용 프로그램에 전용 가상 환경을 사용하는 경우 다른 응용 프로그램을 사용하지 않고 다음 접근 방식을 사용할 수 있습니다.

클래스 rest_framework/authentication.pyauthenticate메소드 에이 코드 가 있기 때문에 관찰 한 일 이 발생합니다 SessionAuthentication.

self.enforce_csrf(request)

CSRF 검사를 원하지 않는 경우 Request속성이 호출 되도록 클래스를 수정하고 csrf_exempt각 View 클래스 내에서 초기화 할 수 있습니다 True. 예를 들면 :

다음으로 위의 코드를 다음과 같이 수정합니다.

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

Request수업 에서해야 할 몇 가지 관련 변경 사항이 있습니다 . 완전한 구현은 여기 (전체 설명 포함)에서 제공됩니다. https://github.com/piaxis/django-rest-framework/commit/1bdb872bac5345202e2f58728d0e7fad70dfd7ed


1

내 솔루션이 타격을 입었습니다. 내 수업을 꾸미세요.

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
이 코드가 질문에 답할 수는 있지만이 코드가 질문에 대한 답변 이유 및 / 또는 방법에 대한 추가 컨텍스트를 제공하면 장기적인 가치가 향상됩니다.
Alex Riabov

1

REST API POST를 사용할 때 X-CSRFToken 요청 헤더가 없으면 해당 오류가 발생할 수 있습니다. Django 문서 는 JS에서 CSRF 토큰 값을 가져오고 설정하는 방법에 대한 샘플 코드를 제공합니다.

위의 답변에서 지적했듯이 CSRF 검사는 SessionAuthentication이 사용될 때 발생합니다. 또 다른 접근 방식은 TokenAuthentication을 사용하는 것이지만 REST_FRAMEWORK 설정의 DEFAULT_AUTHENTICATION_CLASSES 목록에서 첫 번째로 배치해야합니다.


-1

이것은 또한 DNS 리 바인딩 공격 중에 문제가 될 수 있습니다 .

DNS 변경 사이에도 이것이 요인이 될 수 있습니다. DNS가 완전히 플러시 될 때까지 기다리면 DNS 문제 / 변경 전에 작동했다면이 문제가 해결됩니다.


이것이 위의 질문과 무슨 관련이 있습니까?
boatcoder 19.02.15

DNS를 전환 할 때이 문제가 발생할 수 있으며 완전히 전파되지 않았습니다. 앱이 Django 일반 세션과 다른 라우팅을 가지고 있다면 이것이 이유입니다. 내가 만난 엣지 케이스를 알리는 것뿐입니다. 이것은 다소 표준적인 리소스 인 것 같아서 추가 리소스를 추가 할 것이라고 생각했습니다.
chris Frisina
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.