【问题标题】:Can i get Uploadify to work with Django >=1.2.5 using the script-data option to pass CSRF-validation?我可以使用 script-data 选项让 Uploadify 与 Django >=1.2.5 一起工作以通过 CSRF 验证吗?
【发布时间】:2011-08-10 12:59:06
【问题描述】:

由于自 Django 1.2.5 以来 AJAX 请求的 CSRF 策略发生了变化,Uploadify 的所有实现似乎都被破坏了。有一些尝试和一些相当模糊的答案,但还没有解决方案。现在唯一的解决方法似乎是使用 @csrf_exempt 装饰器,正如这篇文章中指出的那样:Fixing django csrf error when using uploadify

虽然 Paul McMillan 指出了这个问题的原因,但他并没有提出解决方案(除了学习 Actionscript 和重写 Uploadify)。对于任何使用 Django 和 jQuery 的人来说,更具体地了解这个主题会很有趣,因为不是每个人都有时间学习 actionscript。我特别好奇是否有使用 Uploadify 的脚本数据选项的解决方案,但我无法开始工作。

$('#fileInput').uploadify({
'uploader'  : '{{ uploadify_path }}uploadify.swf',
'script'    : '{% url uploadify_upload %}',

//this is the interesting line
'scriptData': {"CSRF-Token" : $('input[name="csrfmiddlewaretoken"]').val()}
                },
'cancelImg' : '{{ uploadify_path }}cancel.png',
'auto'      : false,
'folder'    : '{{ upload_path }}',
'multi'     : true,
'onAllComplete' : allComplete
});

我认为这可行,在 script-data 选项中指定的数据确实出现在 request.POST 字典中。我用 pdb 检查并寻找请求:

@csrf_exempt
def upload(request, *args, **kwargs):
    if request.method == 'POST':
        if request.FILES:
            upload_received.send(sender='uploadify', data=request.FILES['Filedata'])
    import pdb; pdb.set_trace();
    return HttpResponse(request)  

结果如下:

<WSGIRequest
GET:<QueryDict: {}>,
POST:<QueryDict: {u'CSRF-Token': [u'de885c962f9a2e50fec140e161ca993e'], u'folder': [u'/static/uploads/'], u'Upload': [u'Submit Query'], u'Filename': [u'P4010040.JPG']}>,
COOKIES:{},
META:{'App 

and so on, the rest as expected  

这与前面提到的帖子的答案中提出的解决方案几乎相同,但该解决方案会破坏 CSRF 保护。我可以以某种方式使用 scriptData 来通过 CSRF 验证,而不会破坏保护吗?我需要哪些信息才能通过验证,如何使用?

编辑:
我提到的帖子使用了这个解决方案,打破了 csrf 保护:

Javascript:

biscuit = document.cookie;
csrt = $('input[name="csrfmiddlewaretoken"]').val();
$('#file_upload').uploadify({
      // pass the cookie and the csrftoken
      scriptData : {biscuit: biscuit, csrfmiddlewaretoken: csrf},
      .... // other codes
 });

中间件:

#insert after: 'django.middleware.common.CommonMiddleware'
def process_request(self, request):
    if (request.method == 'POST'):
       if request.POST.has_key('biscuit'):
          biscuit = request.POST['biscuit']
          tmp = map(lambda x: tuple(x.split("=")), biscuit.split(" "))
          # set a cookie
          request.COOKIES.update(tmp)

如果直接检查 csrfmiddlewaretoken 和 session_id 的正确值怎么办?主要问题是 Django 的 CSRF 保护依赖于 CSRF cookie,并且 uploadify 不通过 cookie。但它可以通过 scriptData 传递 csrfmiddlewaretoken 和 session_id 的值。它不会保留 CSRF 保护,告诉 Django 不要查找 csrf-cookie,而是查找 request.POST 中的相关值吗?

我本质上想说的是:不要盲目设置“饼干”,而是在检查重要值(csrfmiddlewaretoken,sessionid,还有什么?)之后。我认为这可行,尽管我不确定我是否完全理解 csrf 保护的机制......

【问题讨论】:

  • 我很想为此找到一个好的解决方案!只需花 5 个小时尝试,没有任何效果。

标签: jquery django uploadify


【解决方案1】:

我遇到了和你一样的问题。

从 Django 1.2.5 开始,Django 会检查对它的所有请求的 CSRF。原因是谷歌人找到了一种方法来伪造对任何带有自定义标头的 URL 的请求。所以现在验证 Django CSRF 的唯一方法是拥有一个 CSRF_token cookie,或者发送一个 X-CSRFToken 标头,该标头将具有 CSRF 令牌的值。可以在here 找到有关此的发行说明。

据我目前了解,在 Uploadify 中无法修复它,因为 Uploadify 使用 SWFObject 实际发送数据,这是 Flash 并且 Flash 不允许添加自定义标头。

This 上传器纯粹通过使用 XHR 对象发送数据或回退到不支持的浏览器的 iFrame 工作(我没有更改检查解决方案,但当它回退到 iFrame 但它工作完美时使用 XHR 对象)。此外,它是基于 jQuery 的。 Here 是这个上传器如何在 Django 中实现的演示实现,但它仍然是 CSRF 豁免的。

为此演示启用 CSRF 验证的方法是添加从 Django 文档 (here) 为 jQuery 截取的 JS。剪掉的内容是它覆盖了 jQuery 中的默认 AJAX 行为,并且在每个 AJAX 请求上添加了带有 CSRF 令牌值的自定义标头 (X-CSRFToken)。现在由于上传器是基于 jQuery 的,它发出的所有 AJAX 请求都将是 CSRF 有效的。

这里是截图(同样来自 Django 文档):

$(document).ajaxSend(function(event, xhr, settings) {
    function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // 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;
    }
    function sameOrigin(url) {
        // url could be relative or scheme relative or absolute
        var host = document.location.host; // host + port
        var protocol = document.location.protocol;
        var sr_origin = '//' + host;
        var origin = protocol + sr_origin;
        // Allow absolute or scheme relative URLs to same origin
        return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
            (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
            // or any other URL that isn't scheme relative or absolute i.e relative.
            !(/^(\/\/|http:|https:).*/.test(url));
    }
    function safeMethod(method) {
        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }

    if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
        xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
    }
});

希望这会有所帮助。

【讨论】:

  • 抱歉让您久等了。答案真的很好,谢谢。
【解决方案2】:

如果使用csrftoken cookie,则除了上述内容之外,请使用装饰器来确保已设置。

from django.views.decorators.csrf import ensure_csrf_cookie

@ensure_csrf_cookie
def home(request):
     ....

【讨论】:

    猜你喜欢
    • 2023-03-18
    • 1970-01-01
    • 2011-04-17
    • 2021-12-03
    • 1970-01-01
    • 1970-01-01
    • 2012-10-07
    • 1970-01-01
    • 2018-04-26
    相关资源
    最近更新 更多