Django - CSRF 验证失败

29 投票
3 回答
60746 浏览
提问于 2025-04-16 09:08

我在尝试根据一个教程制作简单表单时,遇到了“CSRF验证失败”的提示。我查了一下CSRF验证到底是什么,了解到要使用它,你的HTML里需要有一个csrf_token标签,但我没有这个。

这是我的模板:

<form action="/testapp1/contact/" method="post">
    {{ form.as_p }}
    <input type="submit" value="Submit" />
</form>

这个模板很简单,位于contact.html。

这是我的url配置:

from django.conf.urls.defaults import *
urlpatterns=patterns('testapp1.views',
    (r'^$', 'index'),
    (r'^contact/$','contact')
)

我的应用名称是testapp1。当我输入网址(http://localhost:8000/testapp1/contact)时,可以正常打开表单。但是当我提交表单时,就出现了验证错误。

这是我的视图代码,虽然我觉得这可能不太相关:

def contact(request):
    if request.method == 'POST': # If the form has been submitted...
        form = ContactForm(request.POST) # A form bound to the POST data
        if form.is_valid(): # All validation rules pass
            subject = form.cleaned_data['subject']
            message = form.cleaned_data['message']
            sender = form.cleaned_data['sender']
            cc_myself = form.cleaned_data['cc_myself']
            recipients = ['info@example.com']
            if cc_myself:
                recipients.append(sender)
            print 'Sending Mail:'+subject+','+message+','+sender+','+recipients
            return HttpResponseRedirect('/thanks/') # Redirect after POST
    else:
        form = ContactForm() # An unbound form

    return render_to_response('contact.html', {
        'form': form,
    })

3 个回答

2

针对Django 1.4版本

设置文件:settings.py

MIDDLEWARE_CLASSES = (
...
'django.middleware.csrf.CsrfViewMiddleware',
)

视图文件:view.py

from django.template.defaulttags import csrf_token
from django.shortcuts import render

@csrf_token
def home(request):
    """home page"""
    return render(request,
        'template.html',
            {}
    )

模板文件:template.html

<form action="">
    {% csrf_token %}
....
</form>
3

views.py:

from django.shortcuts import render_to_response
from django.template import RequestContext

def my_view(request):
    return render_to_response('mytemplate.html', context_instance=RequestContext(request)) 

mytemplate.html:

<form action="/someurls/" method="POST">{% csrf_token %}
41

解决方法

1. 在模板中的表单标签里加上 {% csrf_token %}

2. 如果你在使用 Django 1.3 及以上版本,并且出于某种原因使用了 render_to_response,那么要把它换成 render 函数。把下面这个:

# Don't use this on Django 1.3 and above
return render_to_response('contact.html', {'form': form})

换成这个:

return render(request, 'contact.html', {form: form})

render 函数是在 Django 1.3 版本中引入的 - 如果你使用的是很老的版本 比如 1.2 或更早的版本,你必须使用 render_to_response 并且需要一个 RequestContext

# Deprecated since version 2.0
return render_to_response('contact.html', {'form': form},
                   context_instance=RequestContext(request))

什么是 CSRF 保护,为什么我需要它?

CSRF 是一种攻击方式,攻击者可以强迫你的用户做一些不好的事情,比如转账、修改邮箱地址等等:

跨站请求伪造(CSRF)是一种攻击,强迫用户在他们已经登录的网页应用上执行不想要的操作。CSRF 攻击主要针对那些会改变状态的请求,而不是窃取数据,因为攻击者无法看到伪造请求的响应。通过一些社交工程手段(比如通过邮件或聊天发送链接),攻击者可能会欺骗网页应用的用户执行他们想要的操作。如果受害者是普通用户,成功的 CSRF 攻击可以迫使用户执行改变状态的请求,比如转账、修改邮箱地址等。如果受害者是管理员账户,CSRF 攻击可能会危及整个网页应用。来源:开放网页应用安全项目

即使你现在不在乎这些,应用可能会发展壮大,所以最好的做法是保持 CSRF 保护开启。

CSRF 保护不应该是可选的吗?

CSRF 保护是可选的,但默认是开启的(CSRF 中间件默认包含)。你可以关闭它:

  • 通过给特定视图加上 csrf_exempt 装饰器。
  • 通过从 settings.py 的中间件列表中移除 CSRF 中间件,来对所有视图关闭。

如果你在系统范围内关闭了它,可以通过给特定视图加上 csrf_protect 装饰器来重新开启。

撰写回答