详解Django的 csrf_protect() 函数:装饰器,保护跨站请求伪造攻击

  • Post category:Python

csrf_protect()是Django框架中的中间件,用于防止跨站请求伪造(Cross-Site Request Forgery,CSRF),是一个关键的安全措施。在使用Django开发Web应用时,需要保护用户个人信息、数据防止被不良网站盗取。

使用csrf_protect(),可以在表单中添加一组csrf_token,这个token是一种特殊的随机字符串,可以验证提交POST数据是否是合法的。如果提交的POST数据中没有这个token或者这个token不合法,那么请求将被拒绝。该函数还会在Cookie中添加一个csrftoken,在后续发出的POST请求里会带有这个token。

使用方法:

在视图函数的定义处或者URL映射中,添加@csrf_protect装饰器即可使用。如果在全局中间件中开启了csrf保护,则可以不加该装饰器。

from django.views.decorators.csrf import csrf_protect
from django.shortcuts import render

@csrf_protect
def my_view(request):
    # 处理逻辑
    return render(request, 'my_template.html')

另外,也可以使用{% csrf_token %}标签在表单中渲染一个csrf_token。

<form method="post">
    {% csrf_token %}
    <label for="username">Username:</label>
    <input type="text" name="username" required>
    <button type="submit">Submit</button>
</form>

下面介绍两个使用案例:

案例一:

一个用户登录的表单,需要使用csrf_protect()防止CSRF攻击。

from django.views.decorators.csrf import csrf_protect
from django.shortcuts import render
from django.contrib.auth import authenticate, login

@csrf_protect
def login_view(request):
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(request, username=username, password=password)
        if user is not None:
            login(request, user)
            return redirect('home')
        else:
            return render(request, 'login.html', {'error': 'Invalid login details.'})
    else:
        return render(request, 'login.html')

在该视图函数中,如果是POST请求,会从请求数据中获取用户名和密码,调用authenticate()验证登录。使用csrf_protect()装饰器保护该表单,确保功能正常运行。

案例二:

一个包含文件上传的视图,需要使用csrf_protect()判断表单的合法性。

from django.views.decorators.csrf import csrf_protect
from django.shortcuts import render
from django.core.files.storage import FileSystemStorage

@csrf_protect
def upload(request):
    if request.method == 'POST' and request.FILES['file']:
        uploaded_file = request.FILES['file']
        fs = FileSystemStorage()
        filename = fs.save(uploaded_file.name, uploaded_file)
        uploaded_url = fs.url(filename)
        return render(request, 'upload.html', {
            'uploaded_url': uploaded_url
        })
    else:
        return render(request, 'upload.html')

在该视图中,如果是POST请求并且有一个名为’file’的文件上传,那么就将文件存储在文件系统中。如果没有通过CSRF验证,那么请求将被拒绝。