Menu
CoddyTech

CSRF ו-API

חלק מהיחידה ממשקי API של JSON במסלול ה-Django של Coddy. שיעור 6 מתוך 19.

תוכנית אמיתית ששולחת POST /api/tasks/ מקבלת 403 אסור. הגנת CSRF של Django דורשת שכל בקשת POST תכלול אסימון סודי מאחד הדפים שלך, כדי שאתר אחר לא יוכל לגרום לדפדפן של מבקר לשלוח את הטפסים שלך. לתוכנית אין דף כזה ואין לה אסימון.

@csrf_exempt, מתוך django.views.decorators.csrf, משבית את הבדיקה עבור תצוגה אחת:

@csrf_exempt
def webhook(request):
    ...

יש לכך מחיר: כל אתר יכול כעת לגרום לדפדפן של מבקר לשלוח את בקשת ה-POST הזאת. זה בסדר עבור תצוגה שאינה תלויה בזהות המשתמש המחובר, כמו רשימת המשימות. API שפועל בשם המשתמש המחובר משאיר את הגנת CSRF פעילה, והסקריפט שבדף שלו שולח את האסימון בכותרת X-CSRFToken.

challenge icon

אתגר

בינוני

אפשר לתוכניות ליצור משימות ללא אסימון CSRF:

  • POST /api/tasks/ פועל ללא אסימון.
  • רק task_list מוחרגת.

לחצו על Run, ואז הקלידו זאת בכרטיסייה Shell. לפני השינוי יודפס 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))

כל השיעורים ביחידה ממשקי API של JSON

תרגלו בעצמכם: Django אונליין