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トークンが見つからないか正しくありません」という詳細が表示されます。メッセージ。回答から、デフォルトの認証を削除する必要があると結論付けました。
アイリーンテキサス

1
私はトークン認証を使用して非常に類似した状況に遭遇していました。:同じ船に乗って他の誰のためのstackoverflow.com/questions/34789301/...
醸造所の監督

回答:


218

なぜこのエラーが発生しているのですか?

これはSessionAuthentication、DRFで使用されるデフォルトのスキームが原因で発生します。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()、実際の内で発生していたチェックをオーバーライドします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保護をバイパス/無効にするセキュリティリスクではありませんか?
パオロ

1
@Paolo OPは、特定のAPIのCSRF認証を無効にする必要がありました。しかし、はい、csrf保護を無効にするのはセキュリティリスクです。特定のユースケースでセッション認証を無効にする必要がある場合は、このソリューションを使用できます。
Rahul Gupta

@RahulGuptaさん-ビューでcsrf_exemptデコレータをチェックして、それらのビューのenforce_csrfだけを無効にする方法はありませんか?
アビシェク2018年

@Abhishek多分あなたはbixente57によって以下のansを探しています。カスタムビューのcsrfを無効にします。
Rahul Gupta

1
@RahulGupta enforce_csrfを実行したくない場合は、何が最善の方法でしょうか?
ゲーマー、

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
おかげで、これは問題の最も簡単な解決策です。私のAPIはoauth2_providerとトークンを使用しています。
Dat TT

1
ああ、男。CsrfExemptMixinはありましたが、authentication_classes = []がありませんでした。ありがとうございました!
MagicLAMP 2017年

参考までに、authentication_classes行が重要なようです。CsrfExemptMixinの有無にかかわらず、私にとっては同じように機能します。
Dashdrum 2017

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を無効にするDjangoのデコレーター
Syed Faizan

これはpython3とdjango 1.11で私にとってうまくいき、最も簡単に思えます!
madannes

12

役に立つ答えを見つけられなかったすべての人のために。はいSessionAuthenticationAUTHENTICATION CLASSを使用しない場合、DRFは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)とDjango Rest Framework(DRF)を使用する場合、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 Authentication、REST_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

私は同じ問題に悩まされています。私はこのリファレンスに従って、それはうまくいきました。解決策はミドルウェアを作成することです

アプリの1つに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
これにより、Webサイト全体がCSRF攻撃を受けやすくなります。en.wikipedia.org/wiki/Cross-site_request_forgery
Jeanno

1

アプリケーションに専用の仮想環境を使用している場合、他のアプリケーションを効果的に使用せずに次のアプローチを使用できます。

クラスrest_framework/authentication.pyauthenticateメソッドにこのコードがあるため、何が発生したかがわかりますSessionAuthentication

self.enforce_csrf(request)

CSRFチェックが必要ない場合は、Requestクラスを変更してプロパティを呼び出しcsrf_exempt、それぞれのビュークラス内でプロパティを初期化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

0

REST API POSTを使用する場合、X-CSRFTokenリクエストヘッダーがないと、そのエラーが発生する可能性があります。 Djangoドキュメントは、JSからCSRFトークン値を取得および設定するためのサンプルコードを提供します。

上記の回答で指摘したように、SessionAuthenticationを使用すると、CSRFチェックが発生します。もう1つのアプローチはTokenAuthenticationを使用することですが、REST_FRAMEWORK設定のDEFAULT_AUTHENTICATION_CLASSESのリストの最初に配置する必要があることに注意してください。


-1

これは、DNSリバインド攻撃の際にも問題になる可能性があります。

DNSの変更の合間には、これも要因になる可能性があります。DNSが完全にフラッシュされるまで待機すると、DNSの問題や変更の前にDNSが機能していた場合は、これが解決されます。


これは上記の質問とどのように関係していますか?
ボートコーダー2019

この問題は、DNSを切り替えるときに発生する可能性があり、DNSが完全に伝達されていないことを意味します。アプリのルーティングがDjangoの通常のセッションと異なる場合は、これが理由です。私が遭遇したエッジケースを通知するだけです。これはやや標準的なリソースのようですので、リソースを追加すると思いました。
クリスフリシナ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.