Early on in my Express app, I define Multer middleware to be used like this:
const multer = require('multer');
app.post('*', multer({ storage: multer.memoryStorage() }).any());
I'm using multer for file uploads.
The majority of my post request to my app will not require any file uploads and so that middleware is mostly useless most of the time.
Is there any downside or danger to using it like this, or is there some reason why I should just be applying the middleware to post requests that require file uploads?
I would suggest you to not use multer as a middleware for the whole app.
Using multer as a middleware would just be acting as a security threat for your app.
For example. You had two routes:
i. /register (requires an image upload as avatar)
ii. /login (doesnt require any file upload)
Any malicious user could easily use /login to upload malicious files into your destination folder in the app and could possibly act as a huge threat.
Only using the multer middleware in routes where you would do a file upload helps mitigate the risk to uploading unwanted and/or malicious files into the server.
Hope this helps.
Related
I am using csurf as recommended in my Express application to guard against cross sites forgeries. I have registered it globally(illustrated with code below) and so far so good.
Now, I have added multer.js to be able to upload images and as their documentation recommends it, it's more secure to attach multer to each express route where you intend to use.
Now when I do attach multer to my upload routes, I am faced with a 'ForbiddenError: invalid csrf token' and I really don't know why, as my view I am submitting the form from, as a csrf token attached to it.
Below is my code and I would really appreciated any help/suggestions. Thank you all
app.js
const express = require('express');
const csrf = require('csurf');
const csrfProtection = csrf();
const shopRoute = require('../Routes/shop');
const app = express();
app.use(csrfProtection);
app.use(shopRoutes);
routes.js
const express = require('express')
const router = express.Router();
const multer = require('multer');
const controllers = require('../Controllers/shop');
router.post('/upload', multer({storage: multer.memoryStorage(), fileFilter: fileFilter), controller.uploadFunction);
I'm guessing the problem is that when you are uploading a file, the content type of the request becomes multipart/form-data, and you cannot simply pass the csrf token to Express in the body anymore.
The API allows to pass it in the URL though. Try passing the token in the _csrf parameter, that I think should solve your issue. So simply post the form to .../?_csrf={your_token}. Note though that this is slightly less secure than passing your csrf token in the request body, and might be flagged as a potential vulnerability in later penetration tests if you ever have one.
Alternatively, for a little more security, you can also pass it as a request header, but that might be a little trickier on the client side. According to the docs, Express will take the token from the following:
req.body._csrf - typically generated by the body-parser module.
req.query._csrf - a built-in from Express.js to read from the URL query string.
req.headers['csrf-token'] - the CSRF-Token HTTP request header.
req.headers['xsrf-token'] - the XSRF-Token HTTP request header.
req.headers['x-csrf-token'] - the X-CSRF-Token HTTP request header.
req.headers['x-xsrf-token'] - the X-XSRF-Token HTTP request header.
So adding a csrf-token header should also work.
Disclaimer: I don't know multer.js at all, and have very little experience with Express.
So im new on using expressjs, usually i choose Laravel as my backend. but because some certain consideration, i choose expressjs.
On Laravel, when we handling file upload, we can write upload logic everywhere, its your freedom to do that. You can encapsulate it inside your model function, or put it on service, or anywhere you want.
But when i use expressjs, so many articles on internet that recommend us to use multer for upload your file. As my background is using Laravel previously, i found its weird to use multer. Its because multer is a middleware. Why on earth we use middleware to upload our images/files.
With this i cant encapsulate my business logic into one service and its make the code separated and with this thats mean i need to maintain one business logic from multiple place.
Could you explain me why everyone choose multer ?
why dont just upload it to our local storage manually ?( actually for now i dont know how to do this ).
What is pros on mins from using this library ?
multer is a body parsing middleware that handles content type multipart/form-data
That means it parses the raw http request data which are primarily used for file upload, and makes it more accessible (storing on disk / in memory /...) for further processing.
Without multer, you would have to parse the raw data yourself if you want to access the file.
With this i cant encapsulate my business logic into one service and
its make the code separated and with this thats mean i need to
maintain one business logic from multiple place. Could you explain me
why everyone choose multer ?
multer, just like other middlewares, can be used at the root for all routes, but can also be put on only specific routes too.
More on express middleware
First of all, Express/body-parser does not handle file uploads natively, so that is why you see other libraries being loaded to handle them. They are all going to be loaded as middleware so they can be injected into the request and handle that a file was actually uploaded.
Coming from a Symfony background, I understand where you are coming from with wanting to handle things more manually, as I do the same. There are other alternatives to multer; for example I use express-fileupload which allows you to load the the uploading middleware for your entire app, and then you can use req.files to handle your uploads. For example:
// load the file upload library as app middleware
const fileUpload = require('express-fileupload');
app.use(fileUpload({
limits: { fileSize: 50 * 1024 * 1024 },
}));
Then let's say you have a file input named 'foo':
<input name="foo" type="file" />
In your route you would handle it like so:
// now handle a file upload
app.post('/upload', function(req, res) {
console.log(req.files.foo); // the uploaded file object
});
The file-upload documentation has examples for the req.files object as well as options you can pass to the middleware itself.
I am trying to set up image upload for a website with a node.js backend. I am sending the image file as a FormData object on a ajax post request. Can I use Multer without Express to upload the images? If so, how can I do it? (considering that I am not using express I have to manually collect post data)
Do not use multer, use busboy instead.
multer is only a wrapper around busboy to stick into express' middleware system. Multer is however not strcitly required to be used with express, it just is about to fit into express.
So you could use multer by writing some "unwrapping" code. But it is easier to use busboy without unwrapping the wrapping.
There are straightforward examples on the busboy npm page.
They way Multer works on top of express is wired!, why Multer should precede the controller in the chain of Middlewares, which which by design causes the server to upload stuff before the DB operation is even checked?
For instance if there was a post operation to articles, and it contains a bunch of fields one of them is a file.
articleModel{title:String,image:String};
router.post('/', multer, articleController.createArticle);
now at the time the request hits, first thing in the chain is to upload the file in the request, but what if an error happened at the execution of the record to the DB like validation or even duplicates, what if I am going to update the article title only? the old files will be uploaded again?
How to make multer upload the files in the response of the http operation callback?
You can indeed make all kind of stuff before Multer actually process the image:
var upload = multer({
dest: 'uploads/',
fileFilter: function (req, file, cb) {
// only images are allowed
var filetypes = /jpeg|jpg|png/;
var mimetype = filetypes.test(file.mimetype);
var extname = filetypes.test(path.extname(file.originalname).toLowerCase());
if (mimetype && extname) {
return cb(null, true);
}
cb("Error");
}
}).single('localImg');
app.post('/api/file', checkBody, auth, uploadFile, controller.aController);
Take this code for example, you can make all kind of middleware actions BEFORE multer process your file, but multer is a library to process multipart/form-data, not files only, people use multipart for sending files mainly but you can send all kind of data too and it will append them to the body (req.body)
Your question is: "Why multer should upload files before any operation?"
You can execute multer when ever you want, but multer will process the request and get your data into the body. Unless you don't need the body data first hand, you need multer to be in the first middleware.
Your other question is: "what if I am going to update the article title only? the old files will be uploaded again?"
No, it will be uploaded once, if there is any problem with the database, any error or reject, you can always use the filesystem (fs) to remove the file from your server, if you already upload it to a third party system, you can delete it.
Hope it helps
I should implement an upload form
I thought of using bodyparser but I read
http://andrewkelley.me/post/do-not-use-bodyparser-with-express-js.html
so what's the way to upload a file with express using the mean stack ?
may be formidable or other modules ?
That warning is specifically against adding the express.bodyparser middleware to your entire stack as it adds express.multipart to all POST endpoints and therefore file uploads are automatically accepted at all POST endpoints. By default the framework automatically saves any uploaded files to /tmp and so unless you are cleaning them up an attacker could flood your disk with uploaded files.
If you want to avoid using additional modules, what you should do is implement express.multipart on the endpoint(s) where you want to allow file uploads. Here's what I'm talking about:
var express = require("express")
, app = express();
// middleware (no bodyparser here)
app.use(express.json());
app.use(express.urlencoded());
// average GET endpoint
app.get("/", function(req,res) {
res.send('ok');
});
// average POST endpont
app.post("/login", function(req,res) {
res.send('ok');
});
// File upload POST endpoint
app.post('/upload', express.multipart, function(req, res) {
//File upload logic here
//Make sure to delete or move the file accordingly here, otherwise files will pile up in `/tmp`
});
Note the inclusion of express.multipart in the file upload endpoint. This endpoint will now process multipart file uploads, and assuming you handle them correctly they won't be a threat.
Now, having told you all of this, Connect is moving to deprecate multipart due to this exact issue, but there don't seem to be any plans to add a stream based file upload replacement. What they instead recommend is that you use node-multiparty which uses streams to avoid ever placing a file on disk. However, there don't seem to be any good references I can find for using multiparty as a middleware without saving files though, so you'll have to contact the author of multiparty or take a closer look at the API for implementing it with Express.
I created an example that uses Express & Multer - very simple, avoids all Connect warnings
https://github.com/jonjenkins/express-upload