python-requests和django - CSRF验证失败。请求中止

时间:2013-11-27 20:31:43

标签: python django

我有一个django服务器来上传文件,当我使用浏览器时,我可以毫无问题地上传文件。

但是如果我使用python-requests命令,它会告诉我CSRF验证失败。请求中止。 python请求代码如下:

    #upload via HTTP
    file = {"docfile": open(fullfilename, "rb")}
    s = requests.Session()
    r = s.get(dhost)
    r = s.post(dhost, files=file)

如果我执行我的代码,我会得到代码403并且错误CSRF验证失败。请求中止。失败的原因:CSRF令牌丢失或不正确。

但如果我查看我发送的标题,我就会设置cookie:

CaseInsensitiveDict({'Content-Length': u'84169', 
'Accept-Encoding': 'gzip, deflate, compress', 
'Accept': '*/*', 
'User-Agent': 'python-requests/2.0.1 CPython/2.7.3 Linux/3.6.11+', 
'Cookie': 'csrftoken=GOOIsG89i5oMCJO6594algTXooxoUeoL', 
'Content-Type': 'multipart/form-data; boundary=86ada00b4f6c41d5997293cce7a53b6b'})

你能否告诉我应该做些什么才能让它发挥作用?

谢谢,

约翰。

3 个答案:

答案 0 :(得分:12)

实际上一切正常,你只需要了解csrf的工作原理。当您在浏览器中加载页面时,您会在{% csrf_token %}内获得一个csrf令牌,因此当您将数据发送到服务器时,您还会发送csrf令牌。

当您使用请求时,您可以在“获取”中获取Cookie。部分,但您并未将其与您的帖子一起发送。如果没有它,您只需发送一个没有令牌的发布请求,这意味着CSRF验证错误。要解决它,请尝试以下代码:

file = {"docfile": open(fullfilename, "rb")}
s = requests.Session()
r1 = s.get(dhost)
csrf_token = r1.cookies['csrftoken']
r2 = s.post(dhost, files=file, data={'csrfmiddlewaretoken': csrf_token}, headers=dict(Referer=dhost))

如果这仅供您自己使用,您可以使用csrf_exampt在该视图上禁用csrf:

@csrf_exempt
def my_view(request):
   ...whateva...

但请注意,如果您计划启动服务器并向公众开放,这不是推荐的解决方案

答案 1 :(得分:3)

  

如果我使用python-requests命令,它会告诉我CSRF验证   失败。但如果我查看我发送的标题,我就会设置cookie:

  'Content-Length': u'84169', 
  'Accept-Encoding': 'gzip, deflate, compress', 
  'Accept': '/', 
  'User-Agent': 'python-requests/2.0.1 CPython/2.7.3 Linux/3.6.11+',
  'Cookie': 'csrftoken=GOOIsG89i5oMCJO6594algTXooxoUeoL',
  'Content-Type': 'multipart/form-data; boundary=86ada00b4f6c41d5997293cce7a53b6b

您必须将两件东西发回服务器:

1)csrftoken Cookie。

2)以下表格名称/价值对:

"csrfmiddlewaretoken" = "csrf token here"

requests会话将负责为您返回Cookie,但您必须添加表单名称/值对:

sess = requests.Session()
r = sess.get(get_url)
my_csrf_token = r.cookies['csrftoken']

with open('myfile.txt') as f:
    r = sess.post(
        post_url,
        data = {
            "csrfmiddlewaretoken": my_csrf_token,
        },
        files = {"myfile": f}

)

print r.status_code
print r.text

当您的django html模板包含csrf标记时:

<form name="myMessage" 
      method="post" 
      class="signin" 
      action="/myapp/process_form/"
      enctype="multipart/form-data">

{% csrf_token %}

csrf tag被隐藏的表单字段替换:

<input type="hidden" 
       value="RTpun6OhlRehRRa2nAIcTtFJk5WuWsLg" 
       name="csrfmiddlewaretoken">

隐藏表单字段向服务器发送其他名称/值对以及表单创建的所有其他名称/值对。名称为"csrfmiddlewaretoken",值为csrf令牌。 django检查cookie以及表单数据中的名称/值对。

顺便说一句,为了获得用于测试目的的csrf令牌,您可以向看起来像这样的视图发出get请求:

def myview(request):
    from django.middleware.csrf import get_token
    get_token(request)  #This causes django to set the csrftoken cookie in the response

    return HttpResponse('server received GET request')

答案 2 :(得分:-1)

这取决于你想要做什么。

如果您不需要CSRF验证,可以使用csrf_exempt装饰器。

或者您可以创建一个新的csrf_exempt视图,仅用于通过python请求进行访问。