Best way to escape array of data on MysQl nodeJS query - javascript

So I have the following object with is made by data submitted by the user in order to sign up:
var dataToInsert = {
userName: 'Wilson J',
userEmail: 'WilsonJ#gmail.com',
userAddress: '2020 St.',
userCellPhone: '95587412',
}
And I'm using the following query to insert it:
var insertQuery = `INSERT INTO users ( ${Object.keys(dataToInsert).toString()} ) VALUES( '${Object.values(dataToInsert).join("','")}' )`;
Which at the end is taken as:
INSERT INTO
users (
userName,
userEmail,
userAddress,
userCellPhone
)
VALUES
(
'Wilson J',
'WilsonJ#gmail.com',
'2020 St',
95587412
)
So far I'm having a hard time understanding how data escaping works. I'd really appreciate if someone could show me how a SQL Injection could take place with this code and how to prevent it.
I'm using the MysQl npm module and it has this method: mysql.escape() but I would like to find a more automated approach instead of escaping every single value manually.

In this day and age, it's actively discouraged to do anything other than bind variables to your query. See this for more information on other ways to escape data:
connection.query(`
INSERT INTO users ( ${Object.keys(dataToInsert).toString()} ) VALUES (?)`,
Object.values(dataToInsert),
function (error, results, fields) {
if (error) throw error;
// ...
}
);
Word of caution: You wont be able to bind variables to the column names, so unfortunately that part of the query is necessary. Ensure your keys of your dataToInsert are either static, or not from any user input.

Alternatively, you can use ? characters as placeholders for values you would like to have escaped like this: [...]
There is a way. https://github.com/mysqljs/mysql#user-content-escaping-query-values

Related

Node SQL Server IN query not working with request params

I want to run a query in Node SQL Server which is using IN clause. This is the string used for querying 'a','b','c'. This code works fine, but user is passing data so, I can't use it. May lead to attacks:
const dbResult = await request.query(`
SELECT OrderID, ParentSKURefNum, SKURefNum, OrderCompleteTime
FROM ${tables.ORDERS}
WHERE OrderID IN (${idsWithQuotes})
`);
I want to use request.input('OrderIDs', ids) and then code will be like this:
request.input('OrderIDs', ids);
const dbResult = await request.query(`
SELECT OrderID, ParentSKURefNum, SKURefNum, OrderCompleteTime
FROM ${tables.ORDERS}
WHERE OrderID IN (#OrderIDs)
`);
But the code above always shows: No data found. What am I doing wrong? In second situation I also tried removing first and last quote from the string assuming request automatically adds it.
Thanks for your help!
I'm using SQL Server 2012 which doesn't support STRING_SPLIT function to split CSV into some sort of table which then IN operator operates on.
I found it on stack overflow that we can split the values using XML which I didn't really understand but did the trick.
SELECT OrderID, ParentSKURefNum, SKURefNum, OrderCompleteTime
FROM ${tables.ORDERS}
WHERE OrderID IN (
SELECT Split.a.value('.', 'NVARCHAR(MAX)') DATA
FROM
(
SELECT CAST('<X>'+REPLACE(#OrderIDs, ',', '</X><X>')+'</X>' AS xml) AS STRING
) AS A
CROSS APPLY String.nodes('/X') AS Split(a)
)

How to remove <br> tags from string in GraphQL query results

I'm working on a React application that utilizes Apollo and GraphQl to query an external API. My issue is that the data contains strings that have tags in them. I'd like to remove the tags.
The string looks like:
Additionally, Igor works as a driver for a transport company.<br /><br />The spring agricultural works on the land started already and he now supports more expenses.
My response data looks like 'data.loans.lend.values', and so I've tried using the str.replace() method on my data. However, it didn't work. I've probably spent about five hours combing through the web to find a solution, but haven't been able to.
This is what my Apollo query component looks like.
<Query query={kivaLoans} variables={{ country: country, sortBy: sort, limit: limitResults }}>
{({ data, loading, error }) => {
if (loading) return <div><p>Loading...</p></div>;
if (error) return <p>ERROR</p>;
return (
And this is my GraphQL query.
gql`
query ($country: [String], $sortBy: LoanSearchSortByEnum, $limit: Int) {
lend {
loans(filters: {status: fundraising, country: $country}, sortBy: $sortBy, limit: $limit) {
values {
id
plannedExpirationDate
image {
url(customSize: "s900")
}
name
loanFundraisingInfo {
fundedAmount
}
loanAmount
description
loanAmount
}
}
}
}`
Has anyone else encountered this issue before?
if you are receiving data back in a format you don't like, this means the graphql server, a database it leverages, or an api it leverages, is returning data to the graphql server in a format that isn't useful for you. The other possibility is that your server itself is formatting your data in an annoying way. So here are your options:
change your server / data sources as appropriate
do a global replace on the string returned: str.replace(/<b>/g, '').replace(/<\/b>/g, ''). Double check my escape characters, I may have that backwards.
in a string replace, /[what you want replaced]/g = a regex for global detection, across the entire string

MarkLogic: find by property value

I have a MarkLogic 8 database:
declareUpdate();
var book0 = {
id: fn.generateId({qwe: 'book'}),
username: 'book',
password: 'pass'
};
var book1 = {
id: fn.generateId({asd: 'book'}),
username: 'user',
password: 'pass1'
};
xdmp.documentInsert(
'zz' + book0.id,
book0,
xdmp.defaultPermissions(),
['qwe']);
xdmp.documentInsert(
'xx' + book1.id,
book1,
xdmp.defaultPermissions(),
['qwe']);
So I want to find them by name with the Node.js API:
var db = marklogic.createDatabaseClient(connection.connInfo);
var qb = marklogic.queryBuilder;
function findByName(name) {
return db.documents.query(
qb.where(
qb.collection('qwe'),
qb.value('username', name)
)
).result();
}
The problem is that it finds not only user or user0, but also users and if I create a document with username book it will find both book and books.
A values query matches the entire text of a JSON property by stemming each word in the text (if stemming is enabled, which is the default).
Where (as in this case) that's not what you want, you can do either of the following:
Create a string range index (with the root collation if you only need exact matches) for the JSON property
Turn on word searches in the database configuration and use the "unstemmed" option on the query.
If you also turn off stemmed search in the database configuration, you don't have to pass the option (and avoid the extra resource required for both types of indexes).
To limit the configuration change to a specific property, you can configure a field for the property instead of configuring the entire database.
For more background, see:
http://docs.marklogic.com/guide/search-dev/stemming
http://docs.marklogic.com/guide/admin/text_index
http://docs.marklogic.com/cts.jsonPropertyValueQuery?q=cts.jsonPropertyValueQuery&v=8.0&api=true
Hoping that helps,

Nodejs and mysql, multiple criteria in a query

I m actually using the mysql module to query my database and I m facing a problem. In fact, I need to escape a full object and parse it in a query that mysql could understand.
Actually, I have :
getByCriteria: (collectionName, criteria)->
sql = 'SELECT * FROM ?? WHERE ?'
inserts = [collectionName, criteria]
sql = MySql.format(sql, inserts)
deferred = Q.defer()
MysqlAdapter.CONNECTION.query(sql, (err, rows, fields)->
console.log err
if err
deferred.reject(new Error(err))
else
deferred.resolve(rows)
)
return deferred.promise
But the console.log(sql) prints :
SELECT * FROM user WHERE username = 'admin', id=1
So I have guessed that the "Mysql.format" returns a string for the INSERT/UPDATE SQL actions.
How can I do it with mysql, without parsing the entire string with a homemade solution ?
THanks for advance
I'm afraid that MySql.format() is very simple (https://github.com/felixge/node-mysql/blob/master/lib/protocol/SqlString.js#L67) so you'll need to do your own formatting.
Just remember to escape values with MySql.escape() and identifiers with MySql.escapeId()
You'll need something similar to SqlString.objectToValues() https://github.com/felixge/node-mysql/blob/master/lib/protocol/SqlString.js#L109 but with values joined with AND instead of ,

Mongoose: Adding an element to array

I'm using Drywall to create a website.
I'm trying to add a dashboard element to the accounts section of the admin site. The dashboard element is to store an array of dashboards (strings) that the user has access to.
I've managed to successfully add the "dashboards" into the schema and store data in it.
Here's the problem:
I need to be able to add elements to the array. The way the code stands currently replaces the contents of dashboards in the database.
I know I can use $addToSet, but I'm not sure how I'd do that since the fieldsToSet variable is sent to the findByIdAndUpdate() method as a single object.
Here's the snippet of my code:
workflow.on('patchAccount', function() {
var fieldsToSet = {
name: {
first: req.body.first,
middle: req.body.middle,
last: req.body.last,
full: req.body.first +' '+ req.body.last
},
company: req.body.company,
phone: req.body.phone,
zip: req.body.zip,
search: [
req.body.dashboards,
req.body.first,
req.body.middle,
req.body.last,
req.body.company,
req.body.phone,
req.body.zip,
]
};
req.app.db.models.Account.findByIdAndUpdate(req.params.id, fieldsToSet, function(err, account) {
if (err) {
return workflow.emit('exception', err);
}
workflow.outcome.account = account;
return workflow.emit('response');
});
});
Here's a link to the original file: (lines 184-203)
Thanks!
fieldsToSet is a bad name (at least misleading in this case), the parameter is actually update which can take $actions like $addToSet
I don't think you want to set (only) the search field with dashboards. I'm guessing that field is used to index users for a search. So you'll probably wind up doing something like this:
fieldsToSet = {
....all the regular stuff,
$addToSet: {dashboard: req.body.dashboardToAdd}
//I'm not sure that you can add multiple values at once
}
Since this is setting all of the values each time I'm not sure you actually will want to add single dashboard items. Instead you might want to get the full set of dashboards the user has and set the whole array again anyway (what if they removed one?)
fieldsToSet = {
....all the regular stuff,
dashboards: req.body.dashboards
//In this case you'd want to make sure dashboards is an appropriate array
}

Categories

Resources