18

我已阅读Django - CSRF 验证失败以及与 django 和 POST 方法相关的几个问题(和答案)。对我来说最好但不工作的答案之一是https://stackoverflow.com/a/4707639/755319

所有批准的答案都至少表明了三件事:

  1. 使用 RequestContext 作为 render_to_response_call 的第三个参数
  2. 使用 POST 方法在每个表单中添加 {% csrf_token %}
  3. 检查 settings.py 中的 MIDDLEWARE_CLASSES

我完全按照建议做了,但错误仍然出现。我使用 django 1.3.1(来自 ubuntu 12.04 存储库)和 python 2.7(默认来自 ubuntu)

这是我的观点:

# Create your views here.
from django.template import RequestContext
from django.http import HttpResponse
from django.shortcuts import render_to_response
from models import BookModel

def index(request):
    return HttpResponse('Welcome to the library')

def search_form(request):
    return render_to_response('library/search_form.html')

def search(request):
    if request.method=='POST':
        if 'q' in request.POST:
            q=request.POST['q']
            bookModel = BookModel.objects.filter(title__icontains=q)
            result = {'books' : bookModel,}
            return render_to_response('library/search.html', result, context_instance=RequestContext(request))
        else:
            return search_form(request)
    else:
        return search_form(request)

这是我的模板(search_form.html):

{% extends "base.html" %}
{% block content %}
<form action="/library/search/" method="post">
    {% csrf_token %} 
    <input type="text" name="q">
    <input type="submit" value="Search">
</form>
{% endblock %}

我重启了服务器,但是403禁止错误仍然存​​在,告诉CSRF验证失败。

我有两个问题:

  1. 如何修复此错误?
  2. 为什么在 django 中做一个“POST”这么难,我的意思是有什么具体的理由让它如此冗长(我来自 PHP,以前从未发现过这样的问题)?
4

8 回答 8

17

我可能错了,但是我发现上述解决方案相当复杂。

对我有用的只是将我的 csrf 令牌包含到我的发布请求中。

$.ajax({
    type: "POST",
    url: "/reports/",
    data: { csrfmiddlewaretoken: "{{ csrf_token }}",   // < here 
            state:"inactive" 
          },
    success: function() {
        alert("pocohuntus")
        console.log("prototype")
    }
})
于 2013-06-28T01:50:44.877 回答
11

这个答案适用于将来可能遇到同样问题的人。

Django 中表单所需的 CSRF{{csrf_token}}模板标签可防止跨站点请求伪造。CSRF 使客户端浏览器访问过的恶意站点可以向您自己的服务器发出请求。因此,django 提供的 csrf_token 使您的 django 服务器和站点可以很容易地被保护免受这种类型的恶意攻击。如果您的表单不受 csrf_token 保护,django 会返回 403 禁止页面。这是对您网站的一种保护形式,尤其是在没有故意遗漏令牌的情况下。

但在某些情况下,django 站点不想使用 csrf_token 保护其表单。例如,我开发了一个 USSD 应用程序,需要一个视图函数来接收来自 USSD API 的 POST 请求。我们应该注意到 POST 请求不是来自客户端上的表单,因此不可能存在 CSRF 风险,因为恶意站点无法提交请求。POST 请求是在用户拨打 USSD 代码时收到的,而不是在提交表单时收到的。

换句话说,在某些情况下,函数需要获取 POST 请求而不需要 {{csrf_token}}。

Django 为我们提供了一个装饰器@csrf_exempt。此装饰器将视图标记为不受中间件确保的保护。

from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse

@csrf_exempt
def my_view(request):
    return HttpResponse('Hello world')

Django 还提供了另一个与 执行相同功能的装饰器{{csrf_token}},但它不会拒绝传入的请求。这个装饰器是@requires_csrf_token. 例如:

@requires_csrf_token
def my_view(request):
    c = {}
    # ...
    return render(request, "a_template.html", c)

这篇文章中将提到的最后一个装饰器与 {{csrf_token}} 完全相同,它被称为@csrf_protect. 但是,单独使用这个装饰器并不是最佳实践,因为您可能会忘记将它添加到您的视图中。例如:

@csrf_protect
def my_view(request):
    c = {}
    # ...
    return render(request, "a_template.html", c)

以下是一些可以更好地指导和解释的链接。

https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/#module-django.views.decorators.csrf

https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/

http://www.squarefree.com/securitytips/web-developers.html#CSRF

于 2018-01-13T01:48:33.780 回答
5

避免此类问题的最简单方法是使用render快捷方式。

from django.shortcuts import render
# .. your other imports

def search_form(request):
    return render(request, 'library/search_form.html')

def search(request):
    q = request.GET.get('q')
    results = BookModel.objects.all()
    if q:
        results = results.filter(title__icontains=q)
    return render(request, 'library/search.html', {'result': results})
于 2012-05-19T09:44:20.480 回答
3

尝试将 RequestContext 放在 search_form 视图的 render_to_response 中:

context_instance=RequestContext(request)
于 2012-05-19T08:08:30.240 回答
2

响应是 403 bcoz,django 在您发出的每个 POST 请求中都需要一个 csrf 令牌(包含在发布数据中)。

有多种方法可以做到这一点,例如:

从cookie中获取token,方法已在文章中说明,请在此处输入链接描述

或者

您可以使用模板中提供的 {{ csrf_token }} 从 DOM 访问它

所以现在使用第二种方法:

var post_data = {
  ...
  'csrfmiddlewaretoken':"{{ csrf_token }}"
  ...
}
$.ajax({
  url:'url',
  type:'POST'
  data:post_data,
  success:function(data){
    console.log(data);
  },
  error:function(error){
    console.log(error);
  }
});
于 2016-06-19T15:29:11.430 回答
1

您需要使用RequestContext您的回复

例如在view.py文件中

from django.template import RequestContext

def home(request):
    return render_to_response('home.html',RequestContext(request, {}))
于 2015-06-03T10:04:31.927 回答
0

你也可以使用

direct_to_template(request, 'library/search.html', result) 

代替

render_to_response('library/search.html', result, context_instance=RequestContext(request))

因为自动direct_to_template添加RequestContext。但请注意,这direct_to_template将被弃用,django 提议使用 CBV TemplateView

RequestContext允许您使用上下文处理器。这是你的错误:{% csrf_token %}输出空字符串,你得到 403。

于 2012-05-19T08:45:03.290 回答
0

这为我解决了。正如 Django 文档所说,在能够直接将 POST 方法发送到您的 RESTAPI 之前,需要完成一些处理。这是代码:

function getCookie(name) {
    let cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        const cookies = document.cookie.split(';');
        for (let i = 0; i < cookies.length; i++) {
            const cookie = cookies[i].trim();
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

const csrftoken = getCookie('csrftoken');
console.log(csrftoken)





$.ajax({
    method:'POST',
    url:"//127.0.0.1:8000/app/homepage/", /*change it to your api endpoint*/
    headers: {'X-CSRFToken': csrftoken},
    data : { "data" : "3"}
    
   
})

我不能用这个解决方案保证的一件事是安全方面

于 2021-03-27T18:57:10.563 回答