CSRF와 API
Coddy Django 여정의 JSON API 섹션에 포함된 레슨. 19개 중 6번째.
POST /api/tasks/를 보내는 실제 프로그램은 403 Forbidden 응답을 받습니다. Django의 CSRF 보호 기능은 다른 웹사이트가 방문자의 브라우저를 이용해 여러분의 양식을 제출하지 못하도록 모든 POST 요청에 여러분이 직접 만든 페이지에서 가져온 비밀 토큰을 포함하도록 합니다. 프로그램에는 그런 페이지도 토큰도 없습니다.
django.views.decorators.csrf의 @csrf_exempt는 한 뷰에서 검사를 끕니다.
@csrf_exempt
def webhook(request):
...대신 일부 보안을 포기하게 됩니다. 이제 어떤 웹사이트든 방문자의 브라우저가 이 POST 요청을 보내도록 할 수 있습니다. 작업 목록처럼 로그인한 사용자가 누구인지에 따라 동작이 달라지지 않는 뷰에는 괜찮습니다. 로그인한 사용자로 동작하는 API는 CSRF 보호를 유지하고, 해당 페이지의 스크립트가 X-CSRFToken 헤더에 토큰을 보냅니다.
챌린지
중급CSRF 토큰이 없는 프로그램도 작업을 만들 수 있게 하세요. tasks/views.py에서 검사 대상에서 제외하는 것은 task_list뿐이며, 토큰 없이도 POST /api/tasks/가 작동합니다.
아래 줄을 Shell 탭에서 실행하세요. enforce_csrf_checks=True는 테스트 Client가 토큰을 검사하게 합니다. 그러면 403 대신 201이 출력됩니다.
from django.test import Client; print(Client(enforce_csrf_checks=True).post("/api/tasks/", {"title": "Pay rent"}, content_type="application/json").status_code)직접 해보기
import json
from django.http import JsonResponse
from django.shortcuts import render
from .models import Task
def task_to_dict(task):
return {
"id": task.id,
"title": task.title,
"done": task.done,
"priority": task.priority,
}
def home(request):
return render(request, "tasks/home.html", {"tasks": Task.objects.all()})
def stats(request):
data = {
"total": Task.objects.count(),
"done": Task.objects.filter(done=True).count(),
}
return JsonResponse(data)
def task_list(request):
if request.method == "POST":
data = json.loads(request.body)
task = Task.objects.create(
title=data["title"],
priority=data.get("priority", "normal"),
)
return JsonResponse(task_to_dict(task), status=201)
tasks = Task.objects.all()
done = request.GET.get("done")
if done == "true":
tasks = tasks.filter(done=True)
elif done == "false":
tasks = tasks.filter(done=False)
return JsonResponse([task_to_dict(task) for task in tasks], safe=False)
def task_detail(request, pk):
task = Task.objects.filter(pk=pk).first()
if task is None:
return JsonResponse({"error": "Task not found"}, status=404)
return JsonResponse(task_to_dict(task))
JSON API의 모든 레슨
직접 연습해 보세요: Django 플레이그라운드