Node and SQL Injection by using ${variable} on query string - node.js

I was told on a question that Im having a SQL Injection problem.
Here is the question
Node with SQL Server - response with for json path query not responding as expected
and here is my code
let sqlString = `
SELECT codeid, code, validFrom, validTo,
(SELECT dbo.PLprospectAgentCodesComp.productIdentifier, dbo.masterGroupsProducts.productName, dbo.PLprospectAgentCodesComp.compensation
FROM dbo.PLprospectAgentCodesComp INNER JOIN
dbo.masterGroupsProducts ON dbo.PLprospectAgentCodesComp.productIdentifier = dbo.masterGroupsProducts.productIdentifier
WHERE (dbo.PLprospectAgentCodesComp.codeid = dbo.PLprospectAgentCodes.codeid) for json path ) as products
FROM dbo.PLprospectAgentCodes
WHERE (plid = ${userData.plid}) for json path`
let conn = await sql.connect(process.env.DB_CONNSTRING)
let recordset = await conn.query(sqlString)
But I've read at Microsoft, and even on a question on this site, that that format prevents SQL injection.
From MS:
"All values are automatically sanitized against sql injection. This is
because it is rendered as prepared statement, and thus all limitations
imposed in MS SQL on parameters apply. e.g. Column names cannot be
passed/set in statements using variables."
I was trying to use the declare #parameter for the above code, but since my code has several queries that depend one of another, Im using await for each Query... and #parameter is not working. After I process the recordset, other queries will execute.
If my code actually is dangerous for SQL injection, is it possible to sanitize sqlString before the following two lines? The reason I ask is not to change the method in about 50 routes.
let sqlString = `select * from table where userid=${userId}`
Sanitizing code here
let conn = await sql.connect(process.env.DB_CONNSTRING)
let recordset = await conn.query(sqlString)
Thanks.

According to https://tediousjs.github.io/node-mssql/ , "All values are automatically sanitized against sql injection." applies only when you use the ES6 Tagged template literals. You should add the tag sql.query before the template string.
let sqlString = sql.query`select * from mytable where id = ${value}`
For more information on tagged template literals: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates

Related

How to avoid `%` symbol injection using LIKE fuzzy query

I am using like for fuzzy query, here is my code:
let mut q = users::table.into_boxed();
if let Some(email) = data.user.email {
if !email.is_empty() {
q = q.filter(users::email.like(format!("%{}", email)));
dbg_sql!(q);
}
}
If I set email=gmail% while querying, it generates sql like this
SELECT * FROM `users` WHERE (`users`.`email` LIKE ?) -- binds: [\"%gmail%\"]
A % symbol is spliced at the end of sql, and unexpected results are obtained after execution. How to avoid this? Need to escape the email query field, or use other sql queries, how to avoid this in diesel What happens?
You want to escape the corresponding query string by using the corresponding .escape() method.

Adding multiple inputs to query MS SQL Server instance using 'node-mssql' npm package

I would like to query MS SQL Server instance to serve a very simple POST request. I am using nodejs + express. The following code (async version) considers only first input types only and therefore returns error -
let pool = await sql.connect(dbCredentials);
let bookName = "string to be matched" ;
let ranksVal= 10
let result = await pool
.request()
.input("item", sql.VarChar, bookName)
.input("ranksVal", sql.Int , ranksVal)
.query(`select top #ranksVal * from dbTable where book = #item order by counts desc`);
Ideally, the above code should return a result for the following SQL query :
select top 10 * from dbTable where book = "string to be matched" order by counts desc
Alternatively, the following solution works :
let result = await pool
.request()
.input("item", sql.VarChar, bookName)
.query(`select top ${ranksVal} * from dbTable where book = #item order by counts desc`);
But I would like to understand how can we pass multiple values to req.input() method.
Thank you.
To use an expression or a parameter in a TOP values clause you must use parentheses. eg
.query(`select top (#ranksVal) * from dbTable where book = #item order by counts desc`);

Is this type of query safe from sql injection?

let tableName = req.body.tableName
let colName = req.body.col1+","+req.body.col2
sqlString = INSERT INTO ${tableName}(${colName}) VALUES ($1,$2) RETURNING *
No, you are using user's input as is inside a SQL query.
Use some kind of query builder like knex, which has a built in way of escaping user's input properly.

Prepared statement in an array and bind() for X DevAPI

I want the statement to search a number of Ids. Like so.
const idsStr = "41, 42, 43";
const sqlStr = `SELECT * FROM table where id IN (${idsStr})`;
session.sql(sqlStr).execute()
But if I use bind method, it only captures the first instance of the string, the remaining values are ignored.
const idsStr = "41, 42, 43";
const sqlStr = `SELECT * FROM table where id IN (?)`;
session.sql(sqlStr).bind(idsStr).execute()
I want to make prepared statement according to the API currently support so as to avoid SQL injection.
This is a limitation of the API (and the X Plugin itself) and a byproduct of the fact that CRUD expressions support an alternative syntax such as IN [41, 42, 43]. Right now, the only way to do what you want is for the SQL statement itself to contain placeholders for all those ids:
const sqlStr = `SELECT * FROM table where id IN (?, ?, ?)
await session.sql(sqlStr).bind(41, 42, 43).execute()
Of course this does not work if you need a dynamic number of elements in the filtering criteria. In that case, you can resort to something like:
const ids = [41, 42, 43]
const sqlStr = `SELECT * FROM table where id IN (${ids.map(() => '?').join(',')})`
await session.sql(sqlStr).bind(ids).execute()
This is probably a bit convoluted but it's the smartest workaround I can think of at the moment.
In the meantime, maybe you can open a bug report at https://bugs.mysql.com/ using the Connector for Node.js category.
Disclaimer: I'm the lead dev of the MySQL X DevAPI Connector for Node.js

"non-integer constant in ORDER BY" when using pg-promise with named parameters

I am trying to write a simple query using the pgp-promise library. My original implementation looks like:
var bar = function(orderBy){
var qs = 'select * from mytable order by ${orderBy};';
return db.many(qs,{orderBy:orderBy});
}
...
bar('id').then(...)
But this gives an error of non-integer constant in ORDER BY
I have also tried adding quotes aroung ${orderBy} and adding double quotes to the orderBy paramater to no avail. I have a working solution by doing var qs = 'select * from mytable order by "' + orderBy + '";' though it should be obvious why I don't want code like that in the project.
My question: Is there a way to get pg-promise to build a query with an order by clause that isn't vulnerable to sql injection?
Is there a way to get pg-promise to build a query with an order by clause that isn't vulnerable to sql injection?
The value for ORDER BY clause is an SQL name, and it is to be formatted using SQL Names:
const bar = function(orderBy) {
const qs = 'select * from mytable order by ${orderBy:name}';
return db.many(qs, {orderBy});
}
whereas :raw / ^ is injecting raw text, which is vulnerable to SQL injections when it comes from outside, and to be used only for strings that have been created and pre-formatted inside the server.

Resources