8

我使用djangockeditor为 TextEdits 提供所见即所得的体验。我想使用 CKEditor 文件上传功能(在文件浏览器/图像对话框中),但是 CKEditor 上传图像的 POST 只包含文件数据。

这是 CSRF 检查的问题。我在 CKEditor 文档中找不到更改文件上传的 POST 数据的位置,以在 POST 数据中添加 django 的 csrf_token 。

作为一种解决方法,我可以更改 filebrowserUploadUrl 参数以在上传 URL 中包含 csrf 数据,对上传视图使用 @csrf_exempt,并检查 request.GET 参数以检查 csrf。但是这个解决方案安全吗?

无论如何,如果有人知道如何在 CKEditor 文件上传 POST 数据中直接包含 csrf 令牌,我非常感兴趣......

4

6 回答 6

7

您可以注册 dialogDefinition 事件,并完全重写上传选项卡,因此:

CKEDITOR.on('dialogDefinition', function (ev) {
  var dialogName = ev.data.name;
  var dialogDefinition = ev.data.definition;
  if (dialogName == 'image') {
    dialogDefinition.removeContents('Upload');
    dialogDefinition.addContents({
      title: "Upload",
      id: "upload",
      label: "Upload",
      elements: [{
        type: "html",
        html: '<form><input id="imageupload" type="file" name="files[]" />{%csrf_token%}</form>'
      }]
    });
   }
});

这是对我的真实世界版本的未经测试的简化,但希望它显示了这个想法。

这不会在图像对话框中设置 URL 字段,因此单击对话框上的“确定”会给您一条错误消息。您需要在成功上传时进行设置,因此:

CKEDITOR.dialog.getCurrent().getContentElement('info', 'txtUrl').setValue(theURL);
于 2013-11-06T15:36:34.610 回答
3

发送到服务器的额外数据通过 get 请求传递。我试图添加额外的数据,并最终实现了添加到用于发送数据的表单的 url 参数

CKEDITOR.on('dialogDefinition', function(ev)
   {
     var dialogName = ev.data.name;
     var dialogDefinition = ev.data.definition;
     if (dialogName == 'image')
     {
           dialogDefinition.contents[2].elements[0].action += '&pin=123456';
            /* 2 is the upload tab it have two elements 0=apparently is the
            and 1: is the button to perform the upload, in 0 have the action property with the parameters of the get request simply adding the new data               
              */ 

     }
   });
于 2014-07-02T22:21:34.880 回答
2

在通过 CKEditor for Elgg 集成图像上传时,我遇到了类似的问题。我想出的侵入性最小的解决方案是绑定到提交按钮的 onClick 事件并直接从中修改表单:

CKEDITOR.on('dialogDefinition', function (ev) {
    var dialogName = ev.data.name;
    var dialogDefinition = ev.data.definition;

    if (dialogName === 'image') {
        var uploadTab = dialogDefinition.getContents('Upload');

        for (var i = 0; i < uploadTab.elements.length; i++) {
            var el = uploadTab.elements[i];

            if (el.type !== 'fileButton') {
                continue;
            }

            // add onClick for submit button to add inputs or rewrite the URL
            var onClick = el.onclick;

            el.onClick = function(evt) {
                var dialog = this.getDialog();
                var fb = dialog.getContentElement(this['for'][0], this['for'][1]);
                var action = fb.getAction();
                var editor = dialog.getParentEditor();
                editor._.filebrowserSe = this;

                // if using jQuery
                $(fb.getInputElement().getParent().$).append('<input type="hidden" name="foo" value="bar">');

                // modifying the URL
                fb.getInputElement().getParent().$.action = '/my/new/action?with&query&params=1';


                if (onClick && onClick.call(evt.sender, evt) === false) {
                        return false;
                }

                return true;
            };
        }
    }
});
于 2014-10-17T20:03:01.110 回答
1

不编辑ckeditor源代码好像没有办法给ckeditor上传数据添加数据。要修改的源代码是 plugins/dialogui/plugin.js,在 ckeditor 3.6.2 中的第 1440 行附近,其中 ckeditor 创建了上传 iframe 使用的表单。

// ADDED TO CKEDITOR CODE %<
var csrfitems = document.getElementsByName("csrfmiddlewaretoken")
var csrftoken = ""
if(csrfitems.length > 0)
    csrftoken = csrfitems[0].value
// >% END OF ADDED CODE
if ( elementDefinition.size )
    size = elementDefinition.size - ( CKEDITOR.env.ie  ? 7 : 0 );   // "Browse" button is bigger in IE.
frameDocument.$.write( [ '<html dir="' + langDir + '" lang="' + langCode + '"><head><title></title></head><body style="margin: 0; overflow: hidden; background: transparent;">',
'<form enctype="multipart/form-data" method="POST" dir="' + langDir + '" lang="' + langCode + '" action="',
CKEDITOR.tools.htmlEncode( elementDefinition.action ),
'">',
// ADDED TO CKEDITOR CODE
    '<input type="hidden" name="csrfmiddlewaretoken" value="',csrftoken,'"/>',
    // >% END OF ADDED CODE
'<input type="file" name="',
CKEDITOR.tools.htmlEncode( elementDefinition.id || 'cke_upload' ),
'" size="',
CKEDITOR.tools.htmlEncode( size > 0 ? size : "" ),
'" />',
'</form>',

现在我们可以在 ckeditor 中使用 django 安全地上传

于 2012-05-04T21:31:02.577 回答
1

这个问题太老了,但是......

4.5 版您可以在任何请求中添加挂钩

editor.on( 'fileUploadRequest', function( evt ) {
    var xhr = evt.data.fileLoader.xhr;

    xhr.setRequestHeader( 'Cache-Control', 'no-cache' );
    xhr.setRequestHeader( 'csrf header ', 'HEADER' );
    xhr.withCredentials = true;
} );
于 2015-12-10T23:51:33.180 回答
0

如果您通过 HTTPS 在 URL 中发送 CSFR 令牌,那么这样做应该没问题(从安全角度来看),而且处理起来也容易得多。

假设 django 可以读取该变量,或者您可以轻松地修改 django。这些试图改变CKeditor的答案似乎有点太多了。

只要用户浏览器以安全的方式将您的 CSFR_token 发送到服务器,无论是通过 POST 还是 GET 都没有关系。游戏中的安全问题是中间人攻击,即您不希望用户 CSFR_token 以纯文本形式广播。

严格来说,这种数据应该根据 HTTP 规范作为 POST 发送,但这似乎是一种“滥用” GET 协议可能是可以接受的情况,因为您无法以特别优雅的方式控制 CKEditor 代码。

此外,如果 CKEditor 在升级中更改内容,您可能会被抓到,通过 URL 传递令牌将始终有效。

于 2017-10-13T10:28:05.803 回答