What is a CSRF
When the browser sends A request, it will automatically bring the cookie content corresponding to the current domain name and send it to the server. No matter whether the request comes from WEBSITE A or other websites, as long as the request is the link of website A, it will bring the cookie of website A. The browser’s same-origin policy does not prevent CSRF attacks, because the browser does not stop JS sending requests to the server, only intercepting the contents of the response when necessary. Or the browser doesn’t know whether to reject the response until it receives it.
Attack process
After the user logs in to website A, the attacker develops A website B by himself. This website will request website A through JS. For example, when the user clicks A button, js execution will be triggered.
Prevent attacks
- Double Submit Cookie
The attacker exploits the fact that cookies are sent along with HTTP requests. But the attacker doesn’t know what’s inside the cookie.
In Django, you add a hidden CSRFMIDDLEwareToken to a form. When you submit a form, the cookie will be compared. If the cookie is consistent, it will be considered normal. Since each user’s token is different, the JS code on B’s website cannot guess the token content, and comparison is bound to fail, so it can play a preventive role.
- Synchronizer Token
The server saves a session_csrftoken in the database. After the form is submitted, the session_csrftoken in the form is compared with that in the session. If the token in the form is inconsistent with that in the session, it is an attack.
This approach is not difficult to implement, but it is more secure because the site does not have the problem of revealing tokens even if it has an XSS attack.
Djangouses the CsrfViewMiddleware middleware to verify CSRF. By default, The CSRF prevention function is enabled. A POST request does not contain a CSRF field, resulting in a verification failure and error 403. So how do we solve this 403 error?
The solution
1. Remove the CSRF verification of the project
Simply comment out this code, but this is not recommended as it will make our site completely unprotected against CSRF attacks.
2. Add CSRF information to the front-end form
<form enctype="multipart/form-data" method="post" action="{% url 'add_data' %}">
{% csrf_token %}
</form>Copy the code
It is important to note that the back end uses render instead of RenderToResponse so that the cSRF_Token variable is present in the front end and the CSRFToken data is present in the front end cookies and can be used in HTML. This approach is limited to forms and is not supported for Ajax requests.
3. Specify a request to remove CSRF verification
CSRF check can be removed only for the specified route, which can be divided into two cases:
- FBV: Uses functions to implement route processing
# import, can make the request to ignore CSRF verification from the django. Views. Decorators. CSRF import csrf_exempt # in the treatment of the function and the decorators to go @ csrf_exempt def add_data(request): result = {} # TODO return HttpResponse(result)Copy the code
- CBV: Implements routing processing using classes
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
class IndexView(View):
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
return render(request, 'home.html')
def post(self, request, *args, **kwargs):
data = request.POST.get('data')
qr_path = gen_qrcode(data)
return HttpResponse(qr_path)Copy the code
Or place the decorator outside the class in the following way
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
@method_decorator(csrf_exempt, name='dispatch')
class IndexView(View):
def get(self, request, *args, **kwargs):
return render(request, 'home.html')
def post(self, request, *args, **kwargs):
data = request.POST.get('data')
qr_path = gen_qrcode(data)
return HttpResponse(qr_path)Copy the code
4. Add CSRF validation data to all requests (recommended)
All of the above approaches are limited and narrow in scope, and we need a one-size-fits-all approach: make all requests carry CSRF data. Since we use Django templates to render front-end pages, we usually define a base.html first. Other pages are introduced with {% extends “base.html” %}. Add ajax global hooks to base.html and CSRF data on request.
<! DOCTYPE HTML > < HTML > <head> <meta charset=" UTF-8 "> <title>{% block title %} home {% endblock %}</title> <link rel="stylesheet" href="{% static 'css/base.css'%}"> <script SRC = "https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js" > < / script > < script > $. AjaxSetup ({data: {csrfmiddlewaretoken: '{{ csrf_token }}' } }) </script> {% block css %} {% endblock %} </head> <body>Copy the code
If you think my article is ok, you can also scan the following QR code to add my wechat account