不要怂,就是干,撸起袖子干!

Commit 6394c5b6 by Sascha Depold

some sql injection prevention + tests

1 parent 96c7cd90
var Utils = require("./utils") var Utils = require("./utils")
, client = new (require("mysql").Client)()
var QueryGenerator = module.exports = { var QueryGenerator = module.exports = {
/* /*
...@@ -8,9 +9,9 @@ var QueryGenerator = module.exports = { ...@@ -8,9 +9,9 @@ var QueryGenerator = module.exports = {
createTableQuery: function(tableName, attributes, options) { createTableQuery: function(tableName, attributes, options) {
options = options || {} options = options || {}
var query = "CREATE TABLE IF NOT EXISTS `<%= table %>` (<%= attributes%>);" var query = "CREATE TABLE IF NOT EXISTS <%= table %> (<%= attributes%>);"
, attrStr = Utils._.map(attributes, function(dataType, attr) { return Utils.addTicks(attr) + " " + dataType}).join(", ") , attrStr = Utils._.map(attributes, function(dataType, attr) { return Utils.addTicks(attr) + " " + dataType}).join(", ")
, values = {table: tableName, attributes: attrStr} , values = {table: Utils.addTicks(tableName), attributes: attrStr}
return Utils._.template(query)(values) return Utils._.template(query)(values)
}, },
...@@ -18,27 +19,41 @@ var QueryGenerator = module.exports = { ...@@ -18,27 +19,41 @@ var QueryGenerator = module.exports = {
dropTableQuery: function(tableName, options) { dropTableQuery: function(tableName, options) {
options = options || {} options = options || {}
var query = "DROP TABLE IF EXISTS `<%= table %>`;" var query = "DROP TABLE IF EXISTS <%= table %>;"
return Utils._.template(query)({table: tableName}) return Utils._.template(query)({table: Utils.addTicks(tableName)})
}, },
/*
Returns a query for selecting elements in the database <tableName>.
Options:
- attributes -> An array of attributes (e.g. ['name', 'birthday']). Default: *
- where -> A hash with conditions (e.g. {name: 'foo'})
OR an ID as integer
OR a string with conditions (e.g. 'name="foo"').
If you use a string, you have to escape it on your own.
- order -> e.g. 'id DESC'
- group
- limit -> The maximum count you want to get.
- offset -> An offset value to start from. Only useable with limit!
*/
selectQuery: function(tableName, options) { selectQuery: function(tableName, options) {
options = options || {} options = options || {}
options.table = tableName options.table = Utils.addTicks(tableName)
options.attributes = options.attributes && options.attributes.map(function(attr){return Utils.addTicks(attr)}).join(", ")
options.attributes = options.attributes || '*' options.attributes = options.attributes || '*'
var query = "SELECT <%= attributes %> FROM `<%= table %>`" var query = "SELECT <%= attributes %> FROM <%= table %>"
if(options.where) { if(options.where) {
if(Utils.isHash(options.where)) options.where = QueryGenerator.getWhereConditions(options.where)
options.where = QueryGenerator.hashToWhereConditions(values.where)
else if(typeof options.where == 'number')
options.where = Utils.addTicks('id') + "=" + options.where
query += " WHERE <%= where %>" query += " WHERE <%= where %>"
} }
if(options.order) query += " ORDER BY <%= order %>" if(options.order) query += " ORDER BY <%= order %>"
if(options.group) query += " GROUP BY <%= group %>" if(options.group) {
options.group = Utils.addTicks(options.group)
query += " GROUP BY <%= group %>"
}
if(options.limit) { if(options.limit) {
if(options.offset) query += " LIMIT <%= offset %>, <%= limit %>" if(options.offset) query += " LIMIT <%= offset %>, <%= limit %>"
else query += " LIMIT <%= limit %>" else query += " LIMIT <%= limit %>"
...@@ -49,29 +64,44 @@ var QueryGenerator = module.exports = { ...@@ -49,29 +64,44 @@ var QueryGenerator = module.exports = {
return Utils._.template(query)(options) return Utils._.template(query)(options)
}, },
/* /*
Returns an insert into command. Parameters: table name + hash of attribute-value-pairs. Returns an insert into command. Parameters: table name + hash of attribute-value-pairs.
*/ */
insertQuery: function(tableName, attrValueHash) { insertQuery: function(tableName, attrValueHash) {
var query = "INSERT INTO `<%= table %>` (<%= attributes %>) VALUES (<%= values %>)" var query = "INSERT INTO <%= table %> (<%= attributes %>) VALUES (<%= values %>);"
var replacements = { var replacements = {
table: tableName, table: Utils.addTicks(tableName),
attributes: Utils._.keys(attrValueHash).map(function(attr){return Utils.addTicks(attr)}).join(","), attributes: Utils._.keys(attrValueHash).map(function(attr){return Utils.addTicks(attr)}).join(","),
values: Utils._.values(attrValueHash).map(function(value){ values: Utils._.values(attrValueHash).map(function(value){
return Utils.transformValueByDataType(value) return client.escape((value instanceof Date) ? Utils.toSqlDate(value) : value)
}).join(",") }).join(",")
} }
return Utils._.template(query)(replacements) return Utils._.template(query)(replacements)
}, },
// TODO /*
Returns an update query.
Parameters:
- tableName -> Name of the table
- values -> A hash with attribute-value-pairs
- where -> A hash with conditions (e.g. {name: 'foo'})
OR an ID as integer
OR a string with conditions (e.g. 'name="foo"').
If you use a string, you have to escape it on your own.
*/
updateQuery: function(tableName, values, where) { updateQuery: function(tableName, values, where) {
// if(Sequelize.Helper.Hash.isHash(values.values)) var query = "UPDATE <%= table %> SET <%= values %> WHERE <%= where %>"
// values.values = Sequelize.Helper.SQL.hashToWhereConditions(values.values) var replacements = {
// table: Utils.addTicks(tableName),
// query = "UPDATE `%{table}` SET %{values} WHERE `id`=%{id}" values: Utils._.map(values, function(value, key){
return Utils.addTicks(key) + "=" + client.escape((value instanceof Date) ? Utils.toSqlDate(value) : value)
}).join(","),
where: QueryGenerator.getWhereConditions(where)
}
return Utils._.template(query)(replacements)
}, },
// TODO // TODO
...@@ -84,19 +114,26 @@ var QueryGenerator = module.exports = { ...@@ -84,19 +114,26 @@ var QueryGenerator = module.exports = {
// else if(values.limit != null) query += " LIMIT " + values.limit // else if(values.limit != null) query += " LIMIT " + values.limit
}, },
getWhereConditions: function(smth) {
var result = null
if(Utils.isHash(smth))
result = QueryGenerator.hashToWhereConditions(smth)
else if(typeof smth == 'number')
result = Utils.addTicks('id') + "=" + client.escape(smth)
else if(typeof smth == "string")
result = smth
return result
},
/* /*
Takes a hash and transforms it into a mysql where condition: {key: value, key2: value2} ==> key=value AND key2=value2 Takes a hash and transforms it into a mysql where condition: {key: value, key2: value2} ==> key=value AND key2=value2
The values are transformed by the relevant datatype. The values are transformed by the relevant datatype.
*/ */
hashToWhereConditions: function(hash) { hashToWhereConditions: function(hash) {
return Utils._.map(hash, function(value, key) { return Utils._.map(hash, function(value, key) {
var _value = Utils.transformValueByDataType(value) var _value = client.escape(value)
, _key = Utils.addTicks(key) , _key = Utils.addTicks(key)
return (_value == 'NULL') ? _key + " IS NULL" : [_key, _value].join("=") return (_value == 'NULL') ? _key + " IS NULL" : [_key, _value].join("=")
}).join(" AND ") }).join(" AND ")
......
var Utils = module.exports = { var Utils = module.exports = {
_: require("underscore"), _: require("underscore"),
addTicks: function(s) { addTicks: function(s) {
return '`' + s + '`' return '`' + Utils.removeTicks(s) + '`'
},
removeTicks: function(s) {
return s.replace("`", "")
}, },
isHash: function(obj) { isHash: function(obj) {
return (typeof obj == 'object') && !obj.hasOwnProperty('length') return (typeof obj == 'object') && !obj.hasOwnProperty('length')
...@@ -46,7 +49,7 @@ var Utils = module.exports = { ...@@ -46,7 +49,7 @@ var Utils = module.exports = {
return ("'" + value + "'") return ("'" + value + "'")
}, },
asSqlDate: function(date) { toSqlDate: function(date) {
return [ return [
[ [
date.getFullYear(), date.getFullYear(),
......
var assert = require("assert")
, QueryGenerator = require("../../lib/sequelize/query-generator")
, eql = assert.equal
module.exports = {
'create table query': function() {
eql(QueryGenerator.createTableQuery('myTable', {title: 'VARCHAR(255)', name: 'VARCHAR(255)'}), "CREATE TABLE IF NOT EXISTS `myTable` (`title` VARCHAR(255), `name` VARCHAR(255));")
},
'drop table query': function() {
eql(QueryGenerator.dropTableQuery('myTable'), "DROP TABLE IF EXISTS `myTable`;")
},
'select query #default': function() {
eql(QueryGenerator.selectQuery('myTable'), "SELECT * FROM `myTable`;")
},
'select query #attributes': function() {
eql(QueryGenerator.selectQuery('myTable', {attributes: ['id', 'name']}), "SELECT `id`, `name` FROM `myTable`;")
},
'select query #where': function() {
eql(QueryGenerator.selectQuery('myTable', {where: {id: 2}}), "SELECT * FROM `myTable` WHERE `id`=2;")
eql(QueryGenerator.selectQuery('myTable', {where: {name: 'foo'}}), "SELECT * FROM `myTable` WHERE `name`='foo';")
eql(QueryGenerator.selectQuery('myTable', {where: {name: "foo';DROP TABLE myTable;"}}), "SELECT * FROM `myTable` WHERE `name`='foo\\';DROP TABLE myTable;';")
eql(QueryGenerator.selectQuery('myTable', {where: 2}), "SELECT * FROM `myTable` WHERE `id`=2;")
eql(QueryGenerator.selectQuery('myTable', {where: "foo='bar'"}), "SELECT * FROM `myTable` WHERE foo='bar';")
},
'select query #order': function() {
eql(QueryGenerator.selectQuery('myTable', {order: "id DESC"}), "SELECT * FROM `myTable` ORDER BY id DESC;")
},
'select query #group': function() {
eql(QueryGenerator.selectQuery('myTable', {group: "name"}), "SELECT * FROM `myTable` GROUP BY `name`;")
},
'select query #limit': function() {
eql(QueryGenerator.selectQuery('myTable', {limit: 10}), "SELECT * FROM `myTable` LIMIT 10;")
},
'select query #offset': function() {
eql(QueryGenerator.selectQuery('myTable', {limit: 10, offset: 2}), "SELECT * FROM `myTable` LIMIT 2, 10;")
eql(QueryGenerator.selectQuery('myTable', {offset: 2}), "SELECT * FROM `myTable`;")
},
'insert query': function() {
eql(QueryGenerator.insertQuery('myTable', {name: 'foo'}), "INSERT INTO `myTable` (`name`) VALUES ('foo');")
eql(QueryGenerator.insertQuery('myTable', {name: "foo';DROP TABLE myTable;"}), "INSERT INTO `myTable` (`name`) VALUES ('foo\\';DROP TABLE myTable;');")
eql(QueryGenerator.insertQuery('myTable', {name: 'foo', birthday: new Date(2011, 2, 27, 10, 1, 55)}), "INSERT INTO `myTable` (`name`,`birthday`) VALUES ('foo','2011-03-27 10:01:55');")
eql(QueryGenerator.insertQuery('myTable', {name: 'foo', foo: 1}), "INSERT INTO `myTable` (`name`,`foo`) VALUES ('foo',1);")
},
'update query': function() {
eql(
QueryGenerator.updateQuery('myTable', {name: 'foo', birthday: new Date(2011, 2, 27, 10, 1, 55)}, {id: 2}),
"UPDATE `myTable` SET `name`='foo',`birthday`='2011-03-27 10:01:55' WHERE `id`=2"
)
eql(
QueryGenerator.updateQuery('myTable', {name: 'foo', birthday: new Date(2011, 2, 27, 10, 1, 55)}, 2),
"UPDATE `myTable` SET `name`='foo',`birthday`='2011-03-27 10:01:55' WHERE `id`=2"
)
eql(QueryGenerator.updateQuery('myTable', {bar: 2}, {name: 'foo'}), "UPDATE `myTable` SET `bar`=2 WHERE `name`='foo'")
eql(QueryGenerator.updateQuery('myTable', {name: "foo';DROP TABLE myTable;"}, {name: 'foo'}), "UPDATE `myTable` SET `name`='foo\\';DROP TABLE myTable;' WHERE `name`='foo'")
}
}
\ No newline at end of file
var assert = require("assert")
, QueryGenerator = require("../../lib/sequelize/query-generator")
, eql = assert.equal
module.exports = {
'create table query': function() {
eql(QueryGenerator.createTableQuery('myTable', {title: 'VARCHAR(255)', name: 'VARCHAR(255)'}), "CREATE TABLE IF NOT EXISTS `myTable` (`title` VARCHAR(255), `name` VARCHAR(255));")
},
'drop table query': function() {
eql(QueryGenerator.dropTableQuery('myTable'), "DROP TABLE IF EXISTS `myTable`;")
}
}
\ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!