How to deal with SQL Injection in OrientDB using nodejs? - node.js

I'm using the orientjs library to perform operations in the Orient Database. I read in the documentation that it's possible to use parameter-style queries like the following:
db.query(
'SELECT name, ba FROM Player '
+ 'WHERE ba >= :ba AND team = ":team"',
{params: {
ba: targetBA,
team: targetTeam }
}, limit: 20
).then(function(hitters){
console.log(hitters)
});
My question is: Is it enough to prevent SQL injection? Because I didn't find information about that in the NodeJS API. In the case of Java, there is a 'Prepared Query' concept, I'm not sure if they are refering to the same thing.

Seems to be secure, I'm trying with this code (yours taken from the wiki is a bit buggy):
var name='admin';
db.open().then(function() {
return db.query(
"SELECT * FROM OUser "
+ "WHERE name = :name",
{params:{
name: name
}
});
}).then(function(res){
console.log(res);
db.close().then(function(){
console.log('closed');
});
});
First of all, the query is parsed as SELECT * FROM OUser WHERE name = "admin" (observed with the Studio Query Profiler).
As expected, I get the admin user record.
Since the params are evaluated directly as String, there's non need quote them (e.g. :name not ':name'). So there is no way to inject something like ' OR '1'='1 or any ; drop something;
Here are some test I did:
var name='; create class p;';
returns no records;
evaluated by orient as: SELECT * FROM OUser WHERE name = "; create class p;"
var name="' OR '1'='1";
returns no records;
evaluated as: SELECT * FROM OUser WHERE name = "' OR '1'='1"
var name='" OR "1"="1';
returns no records;
evaluated as: SELECT * FROM OUser WHERE name = "\" OR \"1\"=\"1"
quoting the param name in the query: "WHERE name = ':name'"
evaluated as: SELECT * FROM OUser WHERE name = ':name'
Feel free to try more combinations, in my opinion seems quite safe.

Related

How to dynamically build Postgres query from API parameters in Nodejs?

I'm looking for a way to dynamically build a SQL query for an unknown number of API parameters that may come back. As a simple example, consider the following query:
router.get("/someEndpoint", authorizationFunction, async (req, res) => {
let sql = `
SELECT *
FROM some_table
WHERE username = $1
${req.query.since !== undefined ? "AND hire_date >= $2" : ""}
`
const results = await pool.query(sql, [req.query.user, req.query.since]);
}
where pool is defined as
const Pool = require("pg").Pool;
const pool = new Pool({<connection parameters>});
The problem I'm having is that if req.query.since is not provided, then the SQL query only requires a single bound parameter ($1). This is presented as an error that says bind message supplies 2 parameters, but prepared statement "" requires 1. Since I don't know which parameters a user will provide until the time of the query, I'm under the impression that I need to provide all possible value, and let the query figure it out.
I've seen a lot of posts that point to pg-promise as a solution, but I'm wondering if that's necessary. Is there a way that I can solve this with my current setup? Perhaps I'm thinking about the problem incorrectly?
Thanks in advance!
Add a trivial expression text that contains $2 and evaluates to true instead of "", for example
SELECT * FROM some_table WHERE username = $1 AND
${req.query.since !== undefined ? " hire_date >= $2": " (true or $2 = $2)"}
The planner will remove it anyway. Added true or just in case $2 is null.
Still it would be cleaner like this
if (req.query.since !== undefined)
{
let sql = `SELECT * FROM some_table WHERE username = $1 AND hire_date >= $2`;
const results = await pool.query(sql, [req.query.user, req.query.since]);
}
else
{
let sql = `SELECT * FROM some_table WHERE username = $1`;
const results = await pool.query(sql, [req.query.user]);
}
What about SQLi risk BTW?

How to change code to prevent SQL injection in typeorm

I am writing code using nestjs and typeorm.
However, the way I write is vulnerable to SQL injection, so I am changing the code.
//Before
.where(`userId = ${userId}`)
//After
.where(`userId = :userId` , {userId:userId})
I am writing a question because I was changing the code and couldn't find a way to change it for a few cases.
//CASE1
const query1 = `select id, 'normal' as type from user where id = ${userId}`;
const query2 = `select id, 'doctor' as type from doctor where id = ${userId}`;
const finalQuery = await getConnection().query(`select id, type from (${query1} union ${query2}) as f limit ${limit} offset ${offset};`);
//CASE2
...
.addSelect(`CASE WHEN userRole = '${userRole}' THEN ...`, 'userType')
...
//CASE3 -> to find search results in order of accuracy
...
.orderBy(`((LENGTH(user.name) - LENGTH((REPLACE(user.name, '${keyword.replace( / /g, '', )}', '')))) / LENGTH('${keyword.replace(/ /g, '')}'))`,
'ASC')
...
//CASE4
let query = 'xxxx';
let whereQuery = '';
for(const i=0;i<5;i++)
whereQuery += ' or ' + `user.name like '%${keyword}%'`
query.where(whereQuery)
I cannot use parameter in the select function.
In the above case, I am wondering how to change it.
Is it ok to not have to modify the select code?

Querying DocumentDb in .NET with a parametrized query

For an application I'm running a query on DocumentDb in .NET. For this used I wanted to use a parametrized query, like this:
var sqlString = "select p.Id, p.ActionType, p.Type, p.Region, a.TimeStamp, a.Action from History p join a in p.Actions where a.TimeStamp >= #StartTime and a.TimeStamp <= #EndTime and p.ClientId = #ClientId and p.ActionType = #ActionType";
if (actionType != "") { sqlString += actionTypeFilter; }
var queryObject = new SqlQuerySpec
{
QueryText = sqlString,
Parameters = new SqlParameterCollection()
{
new SqlParameter("#StartTime", startDate),
new SqlParameter("#EndTime", endDate),
new SqlParameter("#ClientId", clientId.ToString()),
new SqlParameter("#ActionType", actionType)
},
};
var dataListing = _documentDbClient.CreateDocumentQuery<PnrTransaction>(UriToPnrHistories, queryObject, new FeedOptions() { MaxItemCount = 1 });
When I execute this, I'm getting en empty dataset. But when I use the same query, and build it using classic string replace it works just fine.
Can anyone tell me what I'm doing wrong in my parametrized query?
If the code above is the running code, you still add the actiontypeFilter on the parameterized SQL string. Try to remove the if statement on line 2. Seems to me that may be your problem.
It would help if you could post a sample document from the server.
I usually see this syntax:
SqlParameterCollection parameters = new SqlParameterCollection();
parameters.Add(...);
parameters.Add(...);
Try that and see if you get different results. It might be that the list you use to initialize it in your answer needs to be typed differently to work.

named parameter binding with sql-wildcard not working

I'm using the node-sqlite3 package to access my db.
I'm trying to get rows from a Clients table with this code:
var st = db.prepare("SELECT * FROM Clients where name LIKE '%$name%'");
st.all({ $name: "test" }, function (err, rows) {
console.log("this: " + JSON.stringify(this));
if (err)
console.log(err);
else {
console.log("found: " + JSON.stringify(rows));
}
});
Output of err is this:
{ [Error: SQLITE_RANGE: bind or column index out of range] errno: 25, code: 'SQLITE_RANGE' }
The query works and doesn't throw errors when I change the sql to SELECT * FROM Clients where name LIKE '%$name%'. So I guess the problem is, that node-sqlite3 tries to find a variable called $name% or something like that in the object passed as first parameter to Statement#all.
I've searched the API doc for more hints about this, but couldn't find any.
Do I need to escape something? How do I get my query to work with named binding and the sql wildcards %?
This is not the way bindings work.
You can have
SELECT * FROM Clients where name LIKE $name
and
var name = "%"+"test"+"%";
..
{ $name: name }
bound variables are negociated with the backend database as a "whole" variable and you should not confuse this with variable replacement.
you should also be able to use the concatenate function of sqlite (not tested) :
SELECT * FROM Clients where name LIKE '%'||$name||'%'
..
{ $name: test }

node.js - differences with php

I have the following code in PHP:
$IDs = implode(",", array_keys($result["matches"]));
$sql = "SELECT * FROM table WHERE id IN ($IDs)";
I am "translating" it into Node.js, and I suppose that implode becomes array.join, so I tried this:
var ids = Object.keys(answer['matches']).join(",");
var sql = "SELECT * FROM xml_it WHERE id IN (" + ids + ")";
now, if I echo the PHP $sql variable, I get the expected result:
SELECT * FROM table WHERE id IN (3187,3220,3233,3245,3246,3251,3253,3256, ...
BUT, with node.js, I am getting this:
SELECT * FROM xml_it WHERE id_xml IN ([0,1,2,3,4, ...
The answer['matches'] obviously is the same result (it's basically a Sphinx search result)
Any idea why I am not getting it as a string but the keys?
the data of $result and var answer looks like this:
[{"doc":3187,"weight":1,"attrs":{}},{"doc":3220,"weight":1,"attrs":{}},{"doc":3233,"weight":1,"attrs":{}},
This should work:
var matches = answer['matches'].map( function( o ) {
return o.doc;
});
var ids = matches.join(",");
var sql = "SELECT * FROM xml_it WHERE id IN (" + ids + ")";
gotta map out the doc field since the structure is different

Resources