Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Prevent race condition on unique-submission forms #1841

Merged
merged 1 commit into from Jan 9, 2024

Conversation

susnux
Copy link
Collaborator

@susnux susnux commented Dec 21, 2023

Currently a series of requests can be crafted so that multiple submissions of the same user are inserted.
As the unique property of a submission is only checked once so that if multiple requests arrive at the server right in the same time they will all be inserted.

To prevent this the time window is minimized by placing the check right before the insert and check afterwards if the submission really is unique.

@susnux susnux added bug Something isn't working 3. to review Waiting for reviews feature: 📝 submitting responses labels Dec 21, 2023
@susnux susnux force-pushed the fix/race-condition branch 2 times, most recently from a44fcdd to 81e7ba9 Compare December 21, 2023 13:09
Copy link

codecov bot commented Dec 21, 2023

Codecov Report

Attention: 7 lines in your changes are missing coverage. Please review.

Comparison is base (f24a595) 44.62% compared to head (655762a) 44.61%.
Report is 6 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff              @@
##               main    #1841      +/-   ##
============================================
- Coverage     44.62%   44.61%   -0.01%     
- Complexity      658      662       +4     
============================================
  Files            58       58              
  Lines          2593     2600       +7     
============================================
+ Hits           1157     1160       +3     
- Misses         1436     1440       +4     

@Chartman123
Copy link
Collaborator

@susnux Looks good :) Just a little question: You check all submissions against the new submission for uniqueness. If we have a form with lots of submissions, isn't this very resource consuming?

@susnux
Copy link
Collaborator Author

susnux commented Dec 21, 2023

@Chartman123 I pushed a performance fix, what do you think?

@Chartman123
Copy link
Collaborator

Yes, something like this was on my mind 👍🏻

// Insert new submission
$this->submissionMapper->insert($submission);
$submissionId = $submission->getId();

// Ensure the form is unique if needed.
// If we can not submit anymore then the submission must be unique
if (!$this->formsService->canSubmit($form) && !$this->submissionService->isUniqueSubmission($submission)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (!$this->formsService->canSubmit($form) && !$this->submissionService->isUniqueSubmission($submission)) {
if (!$this->formsService->canSubmit($form) && !$this->submissionService->isUniqueSubmission($submission)) {

Since the first part of this condition already exists up exactly and throws an exception, if this exception exists this part of the code would never be reached?

Or does canSubmit result change after the first insertion?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator Author

@susnux susnux Dec 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is here if the user still can submit after insert then multiple submissions are allowed. If not submissions have to be unique and we need to verify the answer is the only one.

While writing this: Is this not a (unrelated to this PR) bug? If unique submissions are enabled why should the owner be allowed to submit multiple?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why should the owner be allowed to submit multiple?

Good question, the only reason I could think of: The owner fills the form for someone else who can't access the online form for some reason but needs to?

This part of the code was added by @jotoeri 2 years ago. So let's ask him what was his intention :)

Copy link
Member

@jotoeri jotoeri Dec 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, i'm not 100% sure, but i think we shortly discussed that somewhere that once. Otherwise that change wouldn't have gone through just like that.^^
Anyways: I would interpret the Owner as some kind of an administrator for the form, being allowed to do everything with it. The owner could also just remove the submitOnce, submit and then re-set it, which is just annoying handling. So why should we block the owner of doing whatever he/she wants to do with the form?
In fact it's mostly a UX-Question wrt. the owner, no?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Fenn-CS do the comments help you to finish your review?

Copy link
Contributor

@Fenn-CS Fenn-CS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left and inline remark/question to help me review.

@Chartman123
Copy link
Collaborator

by placing the check right before the insert

@susnux One thing that just came to my mind: by moving the check right before the insert, we would check for valid submission data even if a user were no longer allowed to submit. This creates some unnecessary checks in that case.

@susnux
Copy link
Collaborator Author

susnux commented Jan 4, 2024

@susnux One thing that just came to my mind: by moving the check right before the insert, we would check for valid submission data even if a user were no longer allowed to submit. This creates some unnecessary checks in that case.

Well this only happens when using API and not our frontend as the frontend already checks that. Meaning only API usage from external application will cause this.
But yes both cases are not triggered by our frontend but only by (malicious) external usage, so we can discuss both ways.

If we keep the order of the checks the time frame for the attack is a bit wider but as we sanitize afterwards it would be reverted anyways.

@Chartman123
Copy link
Collaborator

For me it's ok to keep it the way you implemented it currently 👍🏻

Copy link
Collaborator

@Chartman123 Chartman123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just squash the fixup commit, then we can merge it from my point of view :)

@Chartman123 Chartman123 added this to the 4.1 milestone Jan 8, 2024
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
@susnux
Copy link
Collaborator Author

susnux commented Jan 8, 2024

Just squash the fixup commit, then we can merge it from my point of view :)

Done

@susnux
Copy link
Collaborator Author

susnux commented Jan 8, 2024

/backport to stable3

@backportbot-nextcloud backportbot-nextcloud bot added the backport-request Pending backport by the backport-bot label Jan 8, 2024
@susnux susnux merged commit 9a7d696 into main Jan 9, 2024
45 of 47 checks passed
@susnux susnux deleted the fix/race-condition branch January 9, 2024 17:13
@backportbot-nextcloud backportbot-nextcloud bot removed the backport-request Pending backport by the backport-bot label Jan 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3. to review Waiting for reviews bug Something isn't working feature: 📝 submitting responses
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants