Reputation: 331
I'm trying to develope simple server in pure NodeJS for my own purposes. The problem I recently realized is that there is a little possibility to go upper or elsewhere from web on my local machine by adding something like ../../../
in path. My server looks like this:
var server = require('http').createServer(function(request, response) {
var file_path = './web' + request.url;
if (file_path == './web/')
file_path = file_path + 'index.html';
var extname = path.extname(file_path);
switch (extname) {
case '.js':
content_type = 'text/javascript';
break;
case '.css':
content_type = 'text/css';
break;
case '.json':
content_type = 'application/json';
break;
default:
content_type = 'text/html';
break;
}
fs.readFile(file_path, 'utf8', function (err, data) {
if (err) {
response.writeHead(404);
return response.end('Error loading ' + request.url);
}
response.writeHead(200, {'Content-Type': content_type});
return response.end(data);
});
});
So I'm wondering what is the best way to protect from such things?
Upvotes: 2
Views: 213
Reputation: 707366
Let's say the root for your web files is /web/files
and you want to make sure that no request outside that hierarchy is processed. You can use path.normalize()
to process all the .
and ..
in it to then check the resulting path like this:
var path = require('path');
var file_path = '/web/files' + request.url;
var resolvedPath = path.normalize(file_path);
if (resolvedPath.indexOf('/web/files/') !== 0) {
// illegal request
}
You can read about path.normalize()
here. It resolves all .
and ..
segements in a path so you can see what the real path will look like and then see if that is still a legal path.
Or, in a utility function:
var path = require('path');
function isPathContained(testPath, containerPath) {
var resolvedPath = path.normalize(fullPath);
return resolvedPath.indexOf(containerPath) === 0;
}
Then, you would use that like this:
var webFiles = '/web/files';
var file_path = webFiles + request.url;
if (!isPathContained(file_path, webFiles)) {
// illegal request
}
Upvotes: 1