Django中的跨站请求伪造(CSRF)保护

2023-04-11 00:00:00 请求 保护 伪造

跨站请求伪造(CSRF)攻击是一种常见的网络攻击,攻击者利用被攻击网站的漏洞,向用户发送带有恶意代码的请求,以获取敏感信息或执行非法操作。为了防止这种攻击,Django提供了内置的CSRF保护机制。

Django的CSRF保护机制基于以下两个原则:

  1. 所有POST、PUT、DELETE等非幂等请求都必须携带CSRF令牌(token)
  2. CSRF令牌必须在服务器端进行验证,才能完成请求

在Django中,使用CSRF保护非常简单。首先,在模板中使用{% csrf_token %}标签生成CSRF令牌:

<form method="post">
    {% csrf_token %}
    ...
</form>

然后,在视图函数中,使用装饰器@csrf_protect来保护表单提交:

from django.views.decorators.csrf import csrf_protect

@csrf_protect
def my_view(request):
    if request.method == 'POST':
        # 处理表单提交
        ...

如果你需要手动生成和验证CSRF令牌,可以分别使用函数csrf.get_token和csrf.verify_csrf:

from django.middleware import csrf

def my_view(request):
    csrf_token = csrf.get_token(request)  # 生成CSRF令牌
    if request.method == 'POST':
        csrf_token_from_form = request.POST.get('csrfmiddlewaretoken', '')  # 从POST数据中获取CSRF令牌
        if not csrf.verify_csrf(csrf_token, csrf_token_from_form):  # 验证CSRF令牌
            # CSRF令牌不匹配,可能是恶意请求
            ...

在代码演示中,以一个简单的表单提交为例:

# forms.py
from django import forms

class MyForm(forms.Form):
    name = forms.CharField(max_length=20)
    email = forms.EmailField()

# views.py
from django.shortcuts import render
from django.middleware import csrf
from .forms import MyForm

def my_view(request):
    if request.method == 'POST':
        form = MyForm(request.POST)
        if form.is_valid():
            # 处理表单提交
            name = form.cleaned_data['name']
            email = form.cleaned_data['email']
            return render(request, 'success.html', {'name': name, 'email': email})
    else:
        form = MyForm()
        csrf_token = csrf.get_token(request)  # 生成CSRF令牌
        return render(request, 'my_form.html', {'form': form, 'csrf_token': csrf_token})

# my_form.html
<form method="post">
    {% csrf_token %}  <!-- 使用标签生成CSRF令牌 -->
    {{ form.as_p }}
    <input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">  <!-- 添加隐藏字段,用于手动获取CSRF令牌 -->
    <input type="submit" name="submit" value="Submit">
</form>

# success.html
<p>Name: {{ name }}</p>
<p>Email: {{ email }}</p>

相关文章