CSRF (Cross-Site Request Forgery) là kiểu tấn công khi site độc hại lừa trình duyệt người dùng (đã đăng nhập site của bạn) gửi request thay đổi dữ liệu thay họ. Token CSRF là chuỗi ngẫu nhiên per-session: server phát ra → client gửi lại trong POST → server so khớp, không khớp là từ chối.
Django bật CsrfViewMiddleware mặc định. Trong template form HTML, chỉ cần chèn {% csrf_token %}:
<form method="post" action="/posts/create/">
{% csrf_token %}
{{ form }}
<button type="submit">Save</button>
</form>Với API/AJAX dùng cookie session, đọc cookie csrftoken rồi gửi qua header X-CSRFToken:
fetch('/api/posts/', {
method: 'POST',
headers: {'X-CSRFToken': getCookie('csrftoken'), 'Content-Type': 'application/json'},
body: JSON.stringify(payload),
})Đừng dán @csrf_exempt chỉ để "cho qua" — đó là tự gỡ áo giáp.
- API token-based ở header (JWT, API key) mới được miễn vì bản thân header đã chống CSRF.
- Webhook bên thứ ba thì phải verify bằng signature HMAC chứ không phải bỏ CSRF.
CSRF (Cross-Site Request Forgery) is when a malicious site tricks the user's browser (already logged into your site) into sending a state-changing request. The CSRF token is a per-session random string: the server issues it → the client returns it in POST → the server verifies the match.
Django enables CsrfViewMiddleware by default. In an HTML form template, include {% csrf_token %}:
<form method="post" action="/posts/create/">
{% csrf_token %}
{{ form }}
<button type="submit">Save</button>
</form>For APIs / AJAX using session cookies: read the csrftoken cookie → send an X-CSRFToken header on POST/PUT/PATCH/DELETE.
fetch('/api/posts/', {
method: 'POST',
headers: {'X-CSRFToken': getCookie('csrftoken'), 'Content-Type': 'application/json'},
body: JSON.stringify(payload),
})Pitfall: Do not @csrf_exempt just to make it work — that is removing the armor.
- JWT/token-based APIs can be exempt (a header-borne token already defends against CSRF).
- Third-party webhooks: use signature verification (HMAC), not bare
@csrf_exempt.