Make using SET or querying system catalogues harder

An hack to "prevent" querying system tables already existed but
was pretty weak. This commits makes that a bit stronger. The
filter for SET is new.
This commit is contained in:
Sandro Santilli 2013-04-09 11:49:05 +02:00
parent bc068a5463
commit 1bcffbc68c
3 changed files with 77 additions and 17 deletions

View File

@ -1,5 +1,6 @@
1.3.8
-----
* Make using SET or querying system catalogues harder
1.3.7
-----

View File

@ -99,15 +99,23 @@ var PSQL = function(user_id, db, limit, offset){
}
};
// throw exception if system table detected
// throw exception if illegal operations are detected
// NOTE: this check is weak hack, better database
// permissions should be used instead.
me.sanitize = function(sql, callback){
if (sql.match(/\s+pg_.+/)){
if (sql.match(/\s+"?pg_.+/i)){
var error = new SyntaxError("system tables are forbidden");
error.http_status = 403;
throw error;
} else {
callback(null,true);
callback(error);
return;
}
if (sql.match(/^\s+set\s+/i)){
var error = new SyntaxError("SET command is forbidden");
error.http_status = 403;
callback(error);
return;
}
callback(null,true);
};
return me;

View File

@ -22,6 +22,7 @@ var app = require(global.settings.app_root + '/app/controllers/app')
, zipfile = require('zipfile')
, fs = require('fs')
, libxmljs = require('libxmljs')
, Step = require('step')
;
// allow lots of emitters to be set to silence warning
@ -621,18 +622,68 @@ test('GET /api/v1/sql ensure cross domain set on errors', function(done){
});
test('cannot GET system tables', function(done){
assert.response(app, {
url: '/api/v1/sql?q=SELECT%20*%20FROM%20pg_attribute',
headers: {host: 'vizzuality.cartodb.com'},
method: 'GET'
},{
status: 403
}, function(res) {
assert.deepEqual(res.headers['content-type'], 'application/json; charset=utf-8');
assert.deepEqual(res.headers['content-disposition'], 'inline');
// TODO: check actual error message...
done();
});
var req = { headers: {host: 'vizzuality.cartodb.com'},
method: 'GET' };
var pre = '/api/v1/sql?';
Step(
function trySysTable1() {
req.url = pre + querystring.stringify({q: 'SELECT * FROM pg_attribute'});
var next = this;
assert.response( app, req, function(res) { next(null, res); } );
},
function chkSysTable1_trySysTable2(err, res) {
if ( err ) throw err;
var next = this;
assert.equal(res.statusCode, 403);
assert.deepEqual(res.headers['content-type'], 'application/json; charset=utf-8');
assert.deepEqual(res.headers['content-disposition'], 'inline');
// TODO: check actual error message...
req.url = pre + querystring.stringify({q: 'SELECT * FROM PG_attribute'});
assert.response(app, req, function(res) { next(null, res); });
},
function chkSysTable2_trySysTable3(err, res) {
if ( err ) throw err;
var next = this;
assert.equal(res.statusCode, 403);
assert.deepEqual(res.headers['content-type'], 'application/json; charset=utf-8');
assert.deepEqual(res.headers['content-disposition'], 'inline');
// TODO: check actual error message...
req.url = pre + querystring.stringify({q: 'SELECT * FROM "pg_attribute"'});
assert.response(app, req, function(res) { next(null, res); });
},
function chkSysTable3_trySet1(err, res) {
if ( err ) throw err;
var next = this;
assert.equal(res.statusCode, 403);
assert.deepEqual(res.headers['content-type'], 'application/json; charset=utf-8');
assert.deepEqual(res.headers['content-disposition'], 'inline');
// TODO: check actual error message...
req.url = pre + querystring.stringify({q: ' set statement_timeout TO 400'});
assert.response(app, req, function(res) { next(null, res); });
},
function chkSet1_trySet2(err, res) {
if ( err ) throw err;
var next = this;
assert.equal(res.statusCode, 403);
assert.deepEqual(res.headers['content-type'], 'application/json; charset=utf-8');
assert.deepEqual(res.headers['content-disposition'], 'inline');
// TODO: check actual error message...
req.url = pre + querystring.stringify({q: ' SET work_mem TO 80000'});
assert.response(app, req, function(res) { next(null, res); });
},
function chkSet2(err, res) {
if ( err ) throw err;
var next = this;
assert.equal(res.statusCode, 403);
assert.deepEqual(res.headers['content-type'], 'application/json; charset=utf-8');
assert.deepEqual(res.headers['content-disposition'], 'inline');
// TODO: check actual error message...
return true;
},
function finish(err) {
done(err);
}
);
});
test('GET decent error if domain is incorrect', function(done){