How do I prevent sql injection on a WHERE IN request with parameterized query? [duplicate] - javascript

I am trying to workout how to pass in a comma sepated string of values into a postgres select within in clause query using node-postgres but unfortunately can't seem to get it working and can't find any examples.
I have the following code:
function getUser() {
let inList = "'qwerty', 'qaz'";
const result = await pgPool.query("SELECT name FROM my_table WHERE info IN ($1)", [inList]);
if (result.rowCount == 1) return result.rows.map(row => row.name)
return false
}
Basically want the end result query to process:
SELECT name FROM my_table WHERE info IN ('qwerty', 'qaz')
Unsure if this is actually the correct way of doing this with pgPool?

The right way is in the FAQ on Github --> https://github.com/brianc/node-postgres/wiki/FAQ#11-how-do-i-build-a-where-foo-in--query-to-find-rows-matching-an-array-of-values
You should be able to do it that way :
pgPool.query("SELECT name FROM my_table WHERE info = ANY ($1)", [jsArray], ...);

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)
)

Filtering in join in supabase

Im using supabase with a database which have 2 tables (that are implicates in this issue).
Tables are teachers and users. Both have ID and id_teacher/id_user respectively.
Im working in a query where i need to get all teacher, joining in users table, where theres a image column.
I need just to get the teachers where the user have an not null image.
const query = supabase.from(`teachers`).select(
`
*,
id_user(
image
)
`
)
This query works to get teachers joining in users table. Because i get my wanted response.
This is a short example.
{
"id": 560,
"teacher_experience": 9,
"id_user":{
"image": "example-image.jpg"
}
}
The trouble is when i try to use some filter to avoid null images.
query.not('id_user.image', 'eq', null)
query.not('id_user.image', 'in', null)
query.ilike('id_user.image', 'null')
Are just an examples o filters tha i tryed for avoid the teachers which user.image have a null value.
Because, i want to NOT GET the entire item, but i get an item wiht a id_user = null
{
"id": 560,
"teacher_experience": 9,
"id_user": null // In this case image is null but still giving me the user
}
How is the correct form to solve this?
Just create a view in database for solve this problem. A view is a shortcut to queries and it possible apply where clause.
In sql editor on supabase https://app.supabase.io/project/{your_project_id}/editor/sql
create a new view with joins;
CREATE VIEW teachers_view AS
SELECT
t.*,
iu.image as image
FROM teachers as t
LEFT JOIN id_user as iu WHERE t.id = iu.teacher_id;
read more about left join here
and in application use
supabase.from('teachers_view').select().neq('image', null);
This has now been implemented with PostgREST 9!
Here's an example:
const { data, error } = await supabase
.from('messages')
.select('*, users!inner(*)')
.eq('users.username', 'Jane'
In your, case you'd have to do id_user!inner(image)
Source: https://supabase.com/blog/postgrest-9#resource-embedding-with-inner-joins
query.not("your_column_name", "is", "NULL")
worked for me!
odd enough, if you want to check for NULL
.filter("your_column_name", "is", "NULL")
seems to be the solution. No idea why it's not consistent
It is not possible atm.
You can see state of issue here.
Some posibilities are using views o start the query in the other table.
The Supabase client uses postgrest, so you can use all sorts of operators in your queries. See this page as a reference.
This feature came up recently with the release of the support for PostgREST 9. You have to use !inner keyword, you can now filter rows of the top-level table.
const query = supabase.from(`teachers`).select(
`
*,
id_user!inner(image)
`
).not("id_users.image", "is", "NULL")
you can try like with inner joins by using the !inner operator in select
const query = supabase.from(`teachers`).select(
`
*,
id_user!inner(
image
)
`
)

TypeORM createQueryBuilder: Is possible to use table name as string instead of entity

In my current scenario, a third party will be creating tables dynamically on my DB, and storing the table name as a varchar and column names as jsonb in other table which is defined as an Entity in my NestJS backend.
This is so I can keep track (and query) these tables, since I have no control over its creation.
For this purpose I'd like to use TypeORM's createQueryBuilder instead of using raw queries as its easier for me to play with abstraction.
As far as I know TypeORMs createQueryBuilder needs a defined Entity in the from clause.
Something like this:
return await getManager()
.createQueryBuilder()
.select('*')
.from(MyDefinedModel, 'modelAlias')
.getRawMany();
}
So I'd like to do something like:
const tableName = await getDynamicallyGenetaredTableNames().getFirstOne()
// now tableName points to a string that is a table name, i.e 'table-data-192239'
return await getManager()
.createQueryBuilder()
.select('*')
.from(tableName, 'tableAlias')
.getRawMany();
So passing the table name I point to the right table, but TypeORM (and TS) complains because that tableName is a string, and not an Entity (Class) type
I really don't want to type-cast and start doing nasty things if there is something cleaner to achieve this.
I didn't find any solution in the official docs
Any brilliant ideas out there?
Thanks, y'all
We can pass table name instead of Entity for getRepository.
let tableName = 'user';
let query = getRepository(tableName).createQueryBuilder(tableName);
You can select from a table by its table name without defining an entity before like this:
const res = await manager
.createQueryBuilder()
.select()
.from("tableName", null)
.where("tableName.id = :id", { id: 1 })
.getRawMany();
Be sure that you set the second parameter of the from() explicitly to null.
You could try using a raw query:
import { getManager } from 'typeorm'
const tableName = await getDynamicallyGenetaredTableNames().getFirstOne()
// Use the table name in a raw SQL query
const result = await getManager().query(`SELECT * FROM ${tableName}`)

How i take a value that is like field in my database?

I try to get values that contains words in my sql database. I try with "contains" but I get an error. I work with SQL
This is my code:
router.post('/busca',isLoggedIn, async (req,res) => {
const {busca} = req.body;
const buscar = Object.values({busca});
const bus = await pool.query('SELECT * FROM links WHERE title CONTAINS ?',[buscar]);
res.render('links/busca',{buscar, bus});
});
I have this error:
UnhandledPromiseRejectionWarning: Error: ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(title, 'a')' at line 1
You can use LIKE operator :
SELECT * FROM links WHERE title LIKE '%word%';
if you are more than one word use and or or operator
SELECT * FROM links WHERE title LIKE '%word%' AND title LIKE '%secondword%';
Contains doesn't exist in mysql .
use LIKE
const bus = await pool.query('SELECT * FROM links WHERE title LIKE ?',[%buscar%]);

get records after creation using sequelize raw query

I am using sequelize for migration. here I execute an INSERT query with following options but its didnot return created records:
const res = oldUsers.map(u => sequelize.query(
`INSERT INTO ${LP_LOCATIONS_TABLE} (name, address, city)
VALUES (
'${u.email}', '${u.address}', '${u.city}');`,
{ type: DataTypes.QueryTypes.INSERT, raw: true },
))
the output is an array of array like below:
[ [[0],[1]] ]
i expect to get created recorders. specially PK. how can I fix it?
I forgot to put RETURNING * at the end of the raw SQL query.
From the doc, you may have to specify the option returning:true to make this happen. I use mySql, so can't test (the returning option is only for postgres).

Categories

Resources