Optimistic Concurrency Control pattern from documentation sometimes lets conflicting writes go through?
See original GitHub issueBug description
Context: Iām building a one-time-password login scheme that generates a 6 digit password and emails it to the user. To prevent brute force attacks, Iām locking an account for 24 hours after 5 failed attempts. So itās really important that attackers donāt get more attempts to crack a password if they send a lot of requests concurrently.
Iām using the Optimistic Concurrency Control pattern shared in the documentation. But seeing that when I write a simple test that makes a bunch of attempts to login concurrently, some conflicting updates are allowed through.
How to reproduce
Repo with code to reproduce the problem: https://github.com/calebmer/prisma-optimistic-concurrency-control-pattern-conflict-repro
Run node repro.js
a couple times. I have an assert with the expected output and it fails for me maybe 2 out of 3 times.
I tried to make a minimal reproducing case, but didnāt remove my domain model. (So the repro is still in the context of one-time-password login.)
Expected behavior
The repro code attempts to login 16 times with incorrect passwords. We should only expose to an attacker that the password was incorrect 5 times and then tell the attacker the account is locked 11 times. (An assert encodes this expectation.)
I donāt have the code for a āsuccessfulā login, but it also uses the Optimistic Concurrency Control pattern and is subject to the same conflicting write issue (which Iāve observed in local tests), effectively giving attackers more attempts to crack the password.
Prisma information
(Prisma schema, version, and queries included in the repro.)
Environment & setup
- OS: MacOS
- Database: PostgreSQL
- Node.js version: v15.0.1
- Prisma version:
prisma : 2.21.2
@prisma/client : 2.21.2
Current platform : darwin
Query Engine : query-engine e421996c87d5f3c8f7eeadd502d4ad402c89464d (at node_modules/@prisma/engines/query-engine-darwin)
Migration Engine : migration-engine-cli e421996c87d5f3c8f7eeadd502d4ad402c89464d (at node_modules/@prisma/engines/migration-engine-darwin)
Introspection Engine : introspection-core e421996c87d5f3c8f7eeadd502d4ad402c89464d (at node_modules/@prisma/engines/introspection-engine-darwin)
Format Binary : prisma-fmt e421996c87d5f3c8f7eeadd502d4ad402c89464d (at node_modules/@prisma/engines/prisma-fmt-darwin)
Default Engines Hash : e421996c87d5f3c8f7eeadd502d4ad402c89464d
Studio : 0.371.0
Issue Analytics
- State:
- Created 2 years ago
- Reactions:1
- Comments:9 (5 by maintainers)
Top GitHub Comments
For more details on my actual code, the āsuccessfully verified password branchā looks something like this:
So it uses the same OOC ācheckā in the where clause but doesnāt need to atomically update any values. Iāve also observed this branch incorrectly fire when testing locally. (Naturally this is the dangerous branch to incorrectly fire since it logs the attacker in.)
Closing. Happy to re-open this discussion if needed though.