Prevent SQL Injection with Nodejs and Postgres - node.js

I'm developing a backend to interact with a PostgreSQL database and am looking for some help preventing SQL injection. I understand the concept of SQL injection, and have found some examples online in preventing those attacks, but not sure if prevention techniques differ between SQL providers.
This is the function I use to query data:
var pg = require("pg");
var client = new pg.Client(connectionString);
client.connect();
module.exports = async function newQuery(query) {
var result = await client.query({
rowMode: 'array',
text: query
});
return result.rows
}
And here are some standard queries using that function (query()):
SELECT
query("SELECT profilename, profiledescription, approved FROM profiledb
WHERE usercompany='"+ req.query.userCompany +"';").then(data => {
res.send(data)
})
UPDATE
query("UPDATE profiledb SET approved='Approved' WHERE id='"+ req.query.id +"';").then(data =>
res.send(data)
)
INSERT
query("INSERT INTO profiledb (profilename, profiledescription, approved) VALUES ('"+
req.query.profileTitle +"', '"+ req.query.profileBody +"', 'Pending');");
What code can I use to query the data without risking SQL injection attack.
Thanks!!!

Use a parameterized query and pass your request arguments as values.
module.exports = async function newQuery(query, values) {
var result = await client.query({
rowMode: 'array',
text: query,
values
});
return result.rows
}
query("SELECT profilename, profiledescription, approved FROM profiledb WHERE usercompany=$1;", [req.query.userCompany]).then(data => {
res.send(data)
});
query("UPDATE profiledb SET approved='Approved' WHERE id=$1;", [req.query.id]).then(data => {
res.send(data)
})
query("INSERT INTO profiledb (profilename, profiledescription, approved) VALUES ($1, $2, 'Pending');", [req.query.profileTitle, req.query.profileBody]);

You should use parameterized queries or prepared statements, just don't concatenate strings yourself ever.
the docs of this specific library are good so i suggest you read them in more details.
queries examples: docs and client.query signature: example
Your query could be written like this:
query("SELECT profilename, profiledescription, approved FROM profiledb
WHERE usercompany = $1", [req.query.userCompany]).then(...)
same is for updates, and inserts etc.
or you can just pass an object with properties: text and values like this
const queryOpts = {
text: "SELECT profilename, profiledescription, approved FROM profiledb WHERE usercompany = $1",
values: [req.query.userCompany]
}
query(queryOpts).then(...)

Related

How to retrieve a sub query in prisma client with same table?

select *
from WeeklyChallengeCourses
where weekly_challenge_id = (select weekly_challenge_id
from WeeklyChallengeCourses
where course_id = 210);
Result will be the below selected one:
const data = await context.prisma.weeklyChallengeCourses.findMany({
where:{
weekly_challenge_id: {
..............
}
},
});
In Prisma, you would have to use two different queries to solve this:
Run an equivalent of the subquery to fetch the weekly_challenge_id
Run a findMany with the weekly_challenge_id found in step 1.
// I'm assuming course_id is unique.
const course = await context.prisma.findUnique({ where: { course_id: 210 } });
const data = await context.prisma.weeklyChallengeCourses.findMany({
where:{
weekly_challenge_id: course.weekly_challenge_id
},
});
Alternatively, you could use the rawQuery feature to run the SQL directly and do it in one query.

show data after inserted using sequelize raw queries in express

I'm trying to send the inserted data with raw queries using sequelize then show it. Below is my code:
const c_product_post = async (req, res) => {
try {
const sql = `INSERT INTO products (p_name, p_price, p_stock, p_review, "createdAt", "updatedAt")
VALUES ('${req.body.product_name}', ${req.body.product_price}, ${req.body.product_stock}, ${req.body.product_review}, now(), now());`
const postData = await Product.sequelize.query(sql)
// await postData.save()
res.send({
message: "success add new product",
data: postData
})
}
catch (err) {
res.send({
message: err
})
}
}
what I'm trying to achieve is that after the data is inserted then it will be shown (see below image in red):
Add RETURNING clause to your query. Try this
INSERT INTO products (p_name, p_price, p_stock, p_review, "createdAt", "updatedAt")
VALUES ('${req.body.product_name}', ${req.body.product_price}, ${req.body.product_stock}, ${req.body.product_review}, now(), now())
RETURNING *;
Please note that your approach is highly SQLi prone. Consider using prepared statements instead of text substitution.

Delay when removing row in postgres with knex

I have a local postgres database running on my machine. I use node.js to access it. I have a table called 'friends' where every row is a user and a friend. I also have a table called 'users' where every row has all basic info about a user(e.g name and such).
When I want to remove a friendship between two users I have to remove two rows from the 'friends' table. I do this with this function:
const removeFriend = async (clientId, friendId) => {
// initiate transaction
return db
.transaction((trx) => {
// remove friendship from client
trx('friends')
.where({ user_id: clientId, friend_id: friendId })
.del()
.then(() => {
// remove friendship from friend
return trx('friends').where({ user_id: friendId, friend_id: clientId }).del();
})
// if all good then commit
.then(trx.commit)
// if bad then rollback
.catch(trx.rollback);
})
.catch(() => 'error');
};
I call the removeFriend function this way removeFriend(clientId, friendId)
Then when i want to get a list of all friends with their names from the database i use this function:
const getUserFriends = async (clientId) => {
// get friends
return db('friends')
.where({ user_id: clientId })
.join('users', 'users.id', 'friends.friend_id')
.select('friends.friend_id', 'users.name')
.then((friends) => friends)
.catch(() => 'error');
};
I call the getUserFriends function this way await getUserFriends(clientId)
The problem is that when I use removeFriend function and then directly use the getUserFriends function i get a list where the users are still friends. However, If i look in the database the rows have been deleted so naturaly i should get a list where the users are not friends. Do I use the await wrong or something?

POST the same UUID into two tables with Node / PostgreSQL

I am trying to make a POST request that will insert the same UUID value into two tables: 'employee' and 'skill'. I have tried this a few different ways, but have not been able to do so. Here is my query for posting the UUID (and a 'summary') into one table:
app.post("/employees/:id/skills", async(req, res) => {
try {
const { summary } = req.body;
const addEmployeeSkill = await pool.query(
"INSERT INTO skill(skill_uuid, summary)VALUES(uuid_generate_v4(), $1) RETURNING *",
[summary],
);
res.json(addEmployeeSkill.rows[0]);
} catch (err) {
console.error(err.message);
}
});
My question is: how do I get the same UUID that is being generated into the 'skill' table to also insert into the skill_uuid column of the 'employee' table?

postgres SELECT query returns unusable result

I have a simple SELECT query that is returning an unusable result. I am using pg-promise in node.js
[
{
"function_name": "(f10d1988-4db5-49de-97ab-0c8b15bedfa7,image.jpg,Image)"
},
{
"function_name": "(f10d1988-4db5-49de-97ab-0c8b15bedfa7,image2.jpg,Image 2)"
}
]
but I was expecting a basic json structure like
[
{
id: '',
title: '',
image: ''
},
{...etc}
]
Why is it doing this? How do I get a normalized result?
My query looks like the below:
CREATE OR REPLACE FUNCTION get_photos(
title_param TEXT
)
RETURNS TABLE(
id UUID,
image varchar(200),
title varchar(200)
) AS
$func$
BEGIN
RETURN QUERY SELECT
i.id,
i.image,
i.title
FROM images AS i
WHERE i.title = title_param;
END;
$func$ LANGUAGE PLPGSQL;
Here is my db conenctor setup, almost all defaults.
require('dotenv').config();
const Promise = require('bluebird');
const pg = require('pg-promise')({
promiseLib: Promise
});
const config = {
user: process.env.USER,
host: process.env.HOST,
database: process.env.DATABASE,
password: process.env.PASSWORD
};
const db = pg(config);
export default db;
Here is the express endpoint that is calling the function:
export const getData = async (req, res) => {
const { title } = req.query;
let data;
try {
data = await db.many('SELECT function_name($1)', [title]);
} catch (err) {
data = err;
}
res.send(data);
};
EDIT
I ran the query manually instead of through a function and the data returned correctly which means that there is an issue with my TABLE() return. What could possibly cause this issue?
images = await db.many(`
SELECT
p.id,
p.img,
p.type,
p.title
FROM photos p
WHERE p.type = '${type}';
`, [type]);
Because the function is defined as returning a table, you need to use it like a table:
SELECT * FROM function_name($1)
Use func as the query method:
data = await db.func('function_name', [title]);
It assumes you return a table, and so will work for you by default.
And for stored procedures, there's proc method.
Also, your parameter formatting for the images query is wrong, see Named Parameters:
IMPORTANT: Never use the reserved ${} syntax inside ES6 template strings ...

Resources