Result of query with comment is inconsistent and random
kkrypt0nn opened this issue · comments
Is there an existing issue for this?
- I have searched the existing issues
Current behavior
Executing the query from the satellite.controller.ts
file with input being:
random') UNION SELECT tbl_name, CAST(1 AS VARCHAR), CAST(1 AS VARCHAR), CAST(1 AS VARCHAR), CAST(1 AS VARCHAR) FROM sqlite_master; --
random
can be replaced with actual random strings
Will either return the correct and expected data or the error
The supplied SQL string contains more than one statement
Minimum reproduction code
https://github.com/kkrypt0nn/nestjs-typeorm-bug
Steps to reproduce
npm i
npm run start:dev
node test.js
As this bug is inconsistent, you may have to run the file multiple times. You will also see that the result will never be the same, sometimes it works sometimes it doesn't - and after attempting the 50 initial requests, sending the same request X
times will make it succeed after some point.
Expected behavior
All the 50 requests made should be working on first attempt and show the actual data and not the error.
Package version
9.0.1
NestJS version
9.3.9
Node.js version
18.15.0 & 19.8.1
In which operating systems have you tested?
- macOS
- Windows
- Linux
Other
Logging with NestJS shows the following query is getting executed (query logged being always the same):
The exact same query being executed multiple times over and over, e.g. by spamming, will make the query return correct data after some time, which makes the bug inconsistent. Here is an example with some frontend on top of it:
228253781-c317b005-9dec-4919-808c-f99c1f667b1e.mp4
Switching the SQLite driver to the sqlite
driver makes the query always work and return the expected result, never the error.
The issue is not happening in better-sqlite3
nor typeorm
themselves as using these standalone do not have the issue. I have attempted the same code and test on both of these without NestJS and it works fine and never throws an error.
PS: I am very well aware that this is prone to SQLi attacks, it is also the purpose of my project: To showcase SQLi vulnerabilities. That is why I have made use of the
dataSource
to make a raw query instead of making use of repositories.
this is not related with @nestjs/typeorm
Please report this to https://github.com/typeorm/typeorm/ instead
As written at the bottom, this does not seem related to typeorm itself because when just using typeorm the issue is not present 🤔
Though I can report it there if you get the issue to occur by just using typeorm, I haven't managed to get it to occur with similar code.
my bad, I missed that line. @nestjs/typeorm
changes nothing on how typeorm works
So this is either an issue with typeorm, or with your code or even with nestjs core
Will make a report at typeorm itself, will see what they say.
Thanks for your time and sorry if this was in the wrong repository ^-^
Before opening an issue there..
So this is either an issue with typeorm, or with your code or even with nestjs core
I doubt the issue is within the code itself, if you want you can look at it it's super basic and simple.
How would it be known if it's an issue with nestjs/core
?
@kkrypt0nn the issue is you use the raw query without parameter... also this is a possible sql injection.
Try to use the query builder (https://typeorm.io/select-query-builder) instead of this raw query or add parameters into your raw query.
The issue is you usage of the raw query without parameter... also this is a possible sql injection.
Try to use the query builder (https://typeorm.io/select-query-builder) instead of this raw query or add parameters into your raw query.
Please take the time to read the PS
at the bottom and how the actual bug occurs ✨
@kkrypt0nn oh sorry my bad 🙈🙈🙈
@kkrypt0nn that's probably an issue with how your test.js
works.
At some iteration, the generated query is probably malformed (from SQL PoV). And since you have no validation on the path param query
, you're suitable to such errors due to how you're using typeorm.
@micalevisk The attempted queries in the test.js
file is always the same, after failing and trying again exactly the same a few times it succeeds. Logging the queries TypeORM is executing shows it's always the same and not some different malformed query.
@kkrypt0nn when trying this without using @nestjs/typeorm
, did you tested the controller->service path as well or just the dataSource.query()
call?
@kkrypt0nn when trying this without using
@nestjs/typeorm
, did you tested the controller->service path as well or just thedataSource.query()
call?
Just the call to the data source
so my bet is that the query
path parameter isn't what you think it is.
can you can try it out again without @nestjs/typeorm
but making the whole path controller -> service -> db query
so my bet is that the
query
path parameter isn't what you think it is.
Well by logging it, it shows what I want it to be - especially when repeating the exact same query multiple times leads to a success after some time.
can you try it out again without
@nestjs/typeorm
but making the whole path controller -> service -> db query
So just the query to the database instead of making use of the dataSource
?
using dataSource
as usual
but you'll create it by yourself instead of relying on @nestjs/typeorm
I was able to use your repo and eventually reproduce the error with typeorm alone using this script
const { DataSource } = require("typeorm");
const dataSource = new DataSource({
type: "better-sqlite3",
database: "db.sqlite",
entities: ["./dist/**/*.entity.js"],
synchronize: true,
});
const main = async () => {
await dataSource.initialize();
for (let i = 0; i < 5000; i++) {
const random = Array.from(Array(20), () =>
Math.floor(Math.random() * 36).toString(36)
).join("");
const searchQuery = `${random}') UNION SELECT tbl_name, CAST(1 AS VARCHAR), CAST(1 AS VARCHAR), CAST(1 AS VARCHAR), CAST(1 AS VARCHAR) FROM sqlite_master; --`;
const query = `SELECT *
FROM user_satellites_satellite
FULL JOIN satellite ON user_satellites_satellite.satelliteId = satellite.id
WHERE user_satellites_satellite.userId = '630633ba-030c-4967-acd4-d790bf26cfda'
AND (satellite.name LIKE '%${searchQuery}%' OR satellite.description LIKE '%${searchQuery}%');`;
const result = await dataSource.query(query);
console.log(result);
}
};
main();
This was after running build
so that the dist
had the proper entities in it. I also had to run it a few time to ensure that the error did happen, as you mentioned it is inconsistent. This is the actual error happening
/home/jay/Documents/code/help/nestjs-typeorm-bug/node_modules/.pnpm/better-sqlite3@8.2.0/node_modules/better-sqlite3/lib/methods/wrappers.js:5
return this[cppdb].prepare(sql, this, false);
^
RangeError: The supplied SQL string contains more than one statement
at Database.prepare (/home/jay/Documents/code/help/nestjs-typeorm-bug/node_modules/.pnpm/better-sqlite3@8.2.0/node_modules/better-sqlite3/lib/methods/wrappers.js:5:21)
at BetterSqlite3QueryRunner.getStmt (/home/jay/Documents/code/help/nestjs-typeorm-bug/node_modules/.pnpm/typeorm@0.3.12_cepfjtr3qct7czdnayem4lr57m/node_modules/typeorm/driver/better-sqlite3/BetterSqlite3QueryRunner.js:37:43)
at async BetterSqlite3QueryRunner.query (/home/jay/Documents/code/help/nestjs-typeorm-bug/node_modules/.pnpm/typeorm@0.3.12_cepfjtr3qct7czdnayem4lr57m/node_modules/typeorm/driver/better-sqlite3/BetterSqlite3QueryRunner.js:74:22)
at async DataSource.query (/home/jay/Documents/code/help/nestjs-typeorm-bug/node_modules/.pnpm/typeorm@0.3.12_cepfjtr3qct7czdnayem4lr57m/node_modules/typeorm/data-source/DataSource.js:341:20)
at async main (/home/jay/Documents/code/help/nestjs-typeorm-bug/test-db.js:22:20)
As this is reproducable without NestJS, this should be reported to TypeORM or better-sqlite3. Not sure which, but probably better-sqlite3
we can probably improve the docs to clarify what is the role of @nestjs/typeorm
(or what it does under the hood).
we can probably improve the docs to clarify what is the role of
@nestjs/typeorm
(or what it does under the hood).
I believe that would be awesome indeed - also many thanks @jmcdo29 :D - my attempted code was most likely different and failed to isolate the issue correctly.
Apologies for the wrongly opened issue from my side.