1
0
記事投稿キャンペーン 「2024年!初アウトプットをしよう」

DjangoでPOSTされなくって沼った話

Last updated at Posted at 2024-01-27

はじめに

Djangoでアプリ外部からPOSTされる処理を実装したので、テスト前にとりあえずcurlでも叩いて実施したところ、200(成功)でも500(エラー)でもなく403(閲覧禁止)が返ってくる事象があった。
しかし、GETでリクエストするとそのロジックは問題なく実行された。メソッド以外に違いがなくDjangoの仕様で沼ったのでその時の対処法をまとめてみた。

実際に書いてたソースのイメージ

以下のように仮に「test」って関数があって、GETかPOSTかによってレスポンス内容を変えて返す関数があり、その関数がurls.pyにルーティングされているとする。

views.py
from django.http import HttpResponse

def test(request):
  if request.method == 'POST':
    return HttpResponse('POST!!')
  else:
    return HttpResponse('GET!!')
urls.py
from django.urls import path

from . import views

app_name = 'test'
urlpatterns = [
    path('test', views.test, name ='test')
]

いざ実際にやってみると・・・

403が返ってきてきた。だがgetだと成功した。
スクリーンショット 2024-01-27 23.22.49.jpg

ちゃんと調べてみると

どうやら画面外からのリクエストなど、Djangoで発行したtokenがないPOSTのリクエストの場合にはPOSTができないらしい。

加えて念の為Django公式をみると「クロスサイトリクエストフォージェリ (CSRF) 対策」ってことで、アプリ側で独自に発行したtokenを持ってないとPOSTはエラーになるよってのがDjangoの仕様としてあるらしい。すごい。

対応したこと

@csrf_exempt」をつけて対応した。
ただ、Django公式にも書いてある通りアプリ側で独自発行したtokenを無効にしているので、Djangoで管理しているtemplateからPOSTする時には使わず、またセッション管理している処理には実装しないなど無闇やらに使うものでもない気がする。

views.py
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt #追加

@csrf_exempt #追加
def test(request):
  if request.method == 'POST':
    return HttpResponse('POST!!')
  else:
    return HttpResponse('GET!!')

再度実行してみた

@csrf_exempt」をつけて対応したところ、ちゃんと200が返ってきた。やったぜ。
スクリーンショット 2024-01-27 23.31.39.jpg

最後に

DjangoがデフォルトでCSRFの脆弱性対応をしてくれてたことで沼ってたが、「@csrf_exempt」は無闇やたらに使ってはいけない奥の手な気がする。
気が向いたら他にいいやり方を模索するかも。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0