mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Merge pull request #319 from hindessm/restrict-library-entry-names
Prohibit library entry names from containing '../'.
This commit is contained in:
commit
b8f40d4e39
@ -34,6 +34,10 @@ function init() {
|
|||||||
res.send(204);
|
res.send(204);
|
||||||
}).otherwise(function(err) {
|
}).otherwise(function(err) {
|
||||||
util.log("[red] Error loading flow '"+req.params[0]+"' : "+err);
|
util.log("[red] Error loading flow '"+req.params[0]+"' : "+err);
|
||||||
|
if (err.message.indexOf('forbidden') === 0) {
|
||||||
|
res.send(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
res.send(500);
|
res.send(500);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -52,6 +56,10 @@ function init() {
|
|||||||
}).otherwise(function(err) {
|
}).otherwise(function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
util.log("[red] Error loading flow '"+req.params[0]+"' : "+err);
|
util.log("[red] Error loading flow '"+req.params[0]+"' : "+err);
|
||||||
|
if (err.message.indexOf('forbidden') === 0) {
|
||||||
|
res.send(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
res.send(404);
|
res.send(404);
|
||||||
});
|
});
|
||||||
@ -75,6 +83,10 @@ function createLibrary(type) {
|
|||||||
}).otherwise(function(err) {
|
}).otherwise(function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
util.log("[red] Error loading library entry '"+path+"' : "+err);
|
util.log("[red] Error loading library entry '"+path+"' : "+err);
|
||||||
|
if (err.message.indexOf('forbidden') === 0) {
|
||||||
|
res.send(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
res.send(404);
|
res.send(404);
|
||||||
});
|
});
|
||||||
@ -91,6 +103,10 @@ function createLibrary(type) {
|
|||||||
res.send(204);
|
res.send(204);
|
||||||
}).otherwise(function(err) {
|
}).otherwise(function(err) {
|
||||||
util.log("[red] Error saving library entry '"+path+"' : "+err);
|
util.log("[red] Error saving library entry '"+path+"' : "+err);
|
||||||
|
if (err.message.indexOf('forbidden') === 0) {
|
||||||
|
res.send(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
res.send(500);
|
res.send(500);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -33,6 +33,10 @@ function moduleSelector(aSettings) {
|
|||||||
return toReturn;
|
return toReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function is_malicious(path) {
|
||||||
|
return path.indexOf('../') != -1 || path.indexOf('..\\') != -1;
|
||||||
|
}
|
||||||
|
|
||||||
var storageModuleInterface = {
|
var storageModuleInterface = {
|
||||||
init : function(settings) {
|
init : function(settings) {
|
||||||
try {
|
try {
|
||||||
@ -58,15 +62,27 @@ var storageModuleInterface = {
|
|||||||
return storageModule.getAllFlows();
|
return storageModule.getAllFlows();
|
||||||
},
|
},
|
||||||
getFlow : function(fn) {
|
getFlow : function(fn) {
|
||||||
|
if (is_malicious(fn)) {
|
||||||
|
return when.reject(new Error('forbidden flow name'));
|
||||||
|
}
|
||||||
return storageModule.getFlow(fn);
|
return storageModule.getFlow(fn);
|
||||||
},
|
},
|
||||||
saveFlow : function(fn, data) {
|
saveFlow : function(fn, data) {
|
||||||
|
if (is_malicious(fn)) {
|
||||||
|
return when.reject(new Error('forbidden flow name'));
|
||||||
|
}
|
||||||
return storageModule.saveFlow(fn, data);
|
return storageModule.saveFlow(fn, data);
|
||||||
},
|
},
|
||||||
getLibraryEntry : function(type, path) {
|
getLibraryEntry : function(type, path) {
|
||||||
|
if (is_malicious(path)) {
|
||||||
|
return when.reject(new Error('forbidden flow name'));
|
||||||
|
}
|
||||||
return storageModule.getLibraryEntry(type, path);
|
return storageModule.getLibraryEntry(type, path);
|
||||||
},
|
},
|
||||||
saveLibraryEntry : function(type, path, meta, body) {
|
saveLibraryEntry : function(type, path, meta, body) {
|
||||||
|
if (is_malicious(path)) {
|
||||||
|
return when.reject(new Error('forbidden flow name'));
|
||||||
|
}
|
||||||
return storageModule.saveLibraryEntry(type, path, meta, body);
|
return storageModule.saveLibraryEntry(type, path, meta, body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,6 +120,27 @@ describe("library", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('returns 403 for malicious access attempt', function(done) {
|
||||||
|
// without the userDir override the malicious url would be
|
||||||
|
// http://127.0.0.1:1880/library/flows/../../package to
|
||||||
|
// obtain package.json from the node-red root.
|
||||||
|
request(RED.httpAdmin)
|
||||||
|
.get('/library/flows/../../../../../package')
|
||||||
|
.expect(403)
|
||||||
|
.end(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns 403 for malicious access attempt', function(done) {
|
||||||
|
// without the userDir override the malicious url would be
|
||||||
|
// http://127.0.0.1:1880/library/flows/../../package to
|
||||||
|
// obtain package.json from the node-red root.
|
||||||
|
request(RED.httpAdmin)
|
||||||
|
.post('/library/flows/../../../../../package')
|
||||||
|
.expect(403)
|
||||||
|
.end(done);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("type", function() {
|
describe("type", function() {
|
||||||
@ -188,5 +209,29 @@ describe("library", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('returns 403 for malicious access attempt', function(done) {
|
||||||
|
request(RED.httpAdmin)
|
||||||
|
.get('/library/test/../../../../../../../../../../etc/passwd')
|
||||||
|
.expect(403)
|
||||||
|
.end(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns 403 for malicious access attempt', function(done) {
|
||||||
|
request(RED.httpAdmin)
|
||||||
|
.get('/library/test/..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\etc\\passwd')
|
||||||
|
.expect(403)
|
||||||
|
.end(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns 403 for malicious access attempt', function(done) {
|
||||||
|
request(RED.httpAdmin)
|
||||||
|
.post('/library/test/../../../../../../../../../../etc/passwd')
|
||||||
|
.set('Content-Type', 'text/plain')
|
||||||
|
.send('root:x:0:0:root:/root:/usr/bin/tclsh')
|
||||||
|
.expect(403)
|
||||||
|
.end(done);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -83,19 +83,19 @@ describe("red/storage/index", function() {
|
|||||||
calledFlagGetAllFlows = true;
|
calledFlagGetAllFlows = true;
|
||||||
},
|
},
|
||||||
getFlow : function(fn) {
|
getFlow : function(fn) {
|
||||||
fn.should.be.true;
|
fn.should.equal("name");
|
||||||
},
|
},
|
||||||
saveFlow : function(fn, data) {
|
saveFlow : function(fn, data) {
|
||||||
fn.should.be.true;
|
fn.should.equal("name");
|
||||||
data.should.be.true;
|
data.should.be.true;
|
||||||
},
|
},
|
||||||
getLibraryEntry : function(type, path) {
|
getLibraryEntry : function(type, path) {
|
||||||
type.should.be.true;
|
type.should.be.true;
|
||||||
path.should.be.true;
|
path.should.equal("name");
|
||||||
},
|
},
|
||||||
saveLibraryEntry : function(type, path, meta, body) {
|
saveLibraryEntry : function(type, path, meta, body) {
|
||||||
type.should.be.true;
|
type.should.be.true;
|
||||||
path.should.be.true;
|
path.should.equal("name");
|
||||||
meta.should.be.true;
|
meta.should.be.true;
|
||||||
body.should.be.true;
|
body.should.be.true;
|
||||||
}
|
}
|
||||||
@ -112,10 +112,10 @@ describe("red/storage/index", function() {
|
|||||||
storage.getCredentials();
|
storage.getCredentials();
|
||||||
storage.saveCredentials(true);
|
storage.saveCredentials(true);
|
||||||
storage.getAllFlows();
|
storage.getAllFlows();
|
||||||
storage.getFlow(true);
|
storage.getFlow("name");
|
||||||
storage.saveFlow(true, true);
|
storage.saveFlow("name", true);
|
||||||
storage.getLibraryEntry(true, true);
|
storage.getLibraryEntry(true, "name");
|
||||||
storage.saveLibraryEntry(true, true, true, true);
|
storage.saveLibraryEntry(true, "name", true, true);
|
||||||
|
|
||||||
calledInit.should.be.true;
|
calledInit.should.be.true;
|
||||||
calledFlagGetFlows.should.be.true;
|
calledFlagGetFlows.should.be.true;
|
||||||
|
Loading…
Reference in New Issue
Block a user