arvindr21 / blueimp-file-upload-expressjs

A simple express module for integrating jQuery File Upload.
http://expressjs-fileupload.cloudno.de/
104 stars 69 forks source link

how does it work well with csurf? #9

Closed wengqianshan closed 10 years ago

wengqianshan commented 10 years ago

I found the request cant't be verified with csurf(https://github.com/expressjs/csurf)

arvindr21 commented 10 years ago

Can you please elaborate what you mean by 'can't be verified'?

I just tested file upload to local setup by installing csurf and using the middleware like

app.use(cookieParser());
app.use(csrf());

And the uploads work fine.

wengqianshan commented 10 years ago

My code is as follows:

node:

app.use(cookieParser());
app.use(session({
    secret: 'some secret'
}));
app.use(csrf());
var uploader = require('blueimp-file-upload-expressjs')(config.upload);
exports.upload = function(req, res) {
    if(req.method === 'GET') {
        res.render('app/upload');
    } else if(req.method === 'POST') {
        uploader.post(req, res, function (obj) {
            res.send(JSON.stringify(obj)); 
        });
    }
};

html:

<input id="fileupload" type="file" name="files[]" data-url="/upload" multiple>

js:

$('#fileupload').fileupload({
                dataType: 'json',
                done: function (e, data) {
                    $.each(data.result.files, function (index, file) {
                        console.log(file)
                    });
                }
            });

Error:

Remote Address:127.0.0.1:7000
Request URL:http://localhost:7000/upload
Request Method:POST
Status Code:403 Forbidden
arvindr21 commented 10 years ago

@xiaoshan5733 I am assuming that csrf is generating a hidden field with a secret key you have mentioned. There is a known issue, where the file upload post is not sending any additional data along with Form request.

wengqianshan commented 10 years ago

@arvindr21 I've tried

$('#fileupload').fileupload({
    formData: {_csrf: '(csrf)'}
});

bug still 403 :-(

arvindr21 commented 10 years ago

@xiaoshan5733 Yup, if you see the request in dev tools, the data is sent from the client. But somehow the server is not able to parse it.

wengqianshan commented 10 years ago

@arvindr21 Oh i see, thanks.

arvindr21 commented 10 years ago

@xiaoshan5733 You can give https://github.com/andrewrk/node-multiparty a try. If csurf works fine, I can update the solution.

wengqianshan commented 10 years ago

@arvindr21 still 403 :-(
This problem will appear as long as the attribute in the form: enctype='multipart/form-data'

arvindr21 commented 10 years ago

@xiaoshan5733 It should work. Can you take a look at http://stackoverflow.com/a/23065983/1015046

wengqianshan commented 10 years ago
var form = new multiparty.Form();
        form.parse(req, function(err, fields, files) {
            res.json(files);
        });
Remote Address:127.0.0.1:7000
Request URL:http://localhost:7000/admin/file/53b17af1f1273ac419c9a8fc/edit
Request Method:POST
Status Code:403 Forbidden
Request Headersview source
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip,deflate,sdch
Accept-Language:zh-CN,zh;q=0.8
Cache-Control:no-cache
Connection:keep-alive
Content-Length:41282
Content-Type:multipart/form-data; boundary=----WebKitFormBoundary0NEWrovHXWsPfa9B
Cookie:XSRF-TOKEN=HPbN8Rln-gHCVEvTitKSKLOnAWyIbA_hyxYA; connect.sid=s%3ABnm8F1d4vm3Re1S79xCBXyBs.y36E9lQbfRwm6cOeqmlaOuJDqNvHNdlc88UOLYuKOdY
Host:localhost:7000
Origin:http://localhost:7000
Pragma:no-cache
Referer:http://localhost:7000/admin/file/53b17af1f1273ac419c9a8fc/edit
User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36
Request Payload
------WebKitFormBoundary0NEWrovHXWsPfa9B
Content-Disposition: form-data; name="file"; filename="tumblr_mvip25ND9p1s3c5cdo1_500.jpg"
Content-Type: image/jpeg

------WebKitFormBoundary0NEWrovHXWsPfa9B
Content-Disposition: form-data; name="description"

ffffff
------WebKitFormBoundary0NEWrovHXWsPfa9B
Content-Disposition: form-data; name="_csrf"

Km5rGktD-eOnseAwugKKUm8AGqI8gxtyTzPM
------WebKitFormBoundary0NEWrovHXWsPfa9B--
arvindr21 commented 10 years ago

Form the above output, I can see that the csurf value is set in the cookie Cookie:XSRF-TOKEN=HPbN8Rln-gHCVEvTitKSKLOnAWyIbA_hyxYA;. So if we can hack the module to read the cookie value for validation, we should be good. I was going through the source and found this.

if (!tokens.verify(secret, value(req))) {
        var err = new Error('invalid csrf token');
        err.status = 403;
        next(err);
        return;
      }

The verify method takes the secret as input. If we set the value of secret from the cookie over here, it "should" work.

BTW the verify method is imported from here

Your thoughts?

wengqianshan commented 10 years ago

Good job! Waiting for your good news. Time to go to bed.

wengqianshan commented 10 years ago

@arvindr21
Hi! I found https://github.com/andrewrk/connect-multiparty works fine.

arvindr21 commented 10 years ago

Oh ok.. Let me see if I can rewrite the file upload code to pass additional form data using connect-multiparty.