Open intech opened 1 year ago
Do you think this issue should be solved in this module, or only in knex adapter, or outside of the lib in the application layer? How it solved in other ORMs like sequelize, Mongoose or others on other language ORMs?
TypeORM uses the lock option in the transaction
Sequelize uses the lock option in the find used version: true
in models and OptimisticLockError
.
Prisma description with issue and PR for query builder methods whereUnique.
There is such a problem as the race condition attack.
This problem is famous when using the ORM pattern as Active Record and Data Mapper. We get a record for changes and change it outside the transaction, which means that we can execute precisely the same query in parallel.
https://github.com/moleculerjs/database/blob/3729bf9c06d1d06d2781abf2f7f7ddf0c435594a/src/methods.js#L592-L595
https://github.com/moleculerjs/database/blob/3729bf9c06d1d06d2781abf2f7f7ddf0c435594a/src/methods.js#L618
Consider a simple attack in transferring $5 from Alice to Bob:
Get balance Alice -> $5 -> transfer to Bob -$5 -> get balance Bob -> $0 -> received from Alice +$5
And now, if two queries were running at the same time:
Query 1:
Get balance Alice -> $5 (race condition!) -> transfer to Bob -$5 -> get balance Bob -> $0 -> received from Alice +$5
Query 2:
Get balance Alice -> $5 (race condition!) -> transfer to Bob -$5 -> get balance Bob -> $5 -> recieved from Alice +$5
Bob has a balance of $10, and Alice has $5.
It is elementary to check this behaviour by calling the
Promise.all()
method, we generate ten requests and, depending on the network, and the processing speed of the database, from 2 to 10 requests will pass simultaneously.In SQL, the first statement must be with
SELECT FOR UPDATE
to block against concurrent updates, or both wrapped in aSERIALIZABLE
transaction isolation level.How can we protect ourselves now?
We must wrap the
updateEntity
method in a transaction with isolation levelSERIALIZABLE
. Or use moleculer-channels to update items in strong FIFO in Kafka.