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

Race condition in Redis backend / design issue with the Backend type #7

Open
mbg opened this issue Jun 3, 2022 · 3 comments
Open

Comments

@mbg
Copy link
Owner

mbg commented Jun 3, 2022

Initially reported for wai-rate-limit-postgres by @chshersh and then @donatello for wai-rate-limit-redis over in donatello/wai-rate-limit-postgres#7 (comment). The problem for wai-rate-limit-redis specifically is that EXPIRE will not create the key if it doesn't already exist, which might be the case if it has expired between the calls to backendIncAndGetUsage and backendExpireIn.

More generally, the problem extends to other backends, such as wai-rate-limit-postgres, since there is no way to run the two transactionally.

@qwbarch
Copy link

qwbarch commented Jan 11, 2023

Is this library safe to use while this race condition exists?
I love the design of this library! Just want to make sure it's good for production use

@mbg
Copy link
Owner Author

mbg commented Jan 16, 2023

Hi @qwbarch, sorry for the slight delay in getting back to you -- I somehow missed the notification for your reply here -- and sorry for not fixing this bug yet.

To answer your question, it somewhat depends on which rate limiting strategy you plan to use and how much you care about strict enforcement of the policies. Generally speaking, I'd think that the library is safe to use until this is fixed.

For the fixed window strategy, the race condition doesn't matter, because it will only call backendIncAndGetUsage once initially.

For the sliding window strategy, the race conditions comes into play if:

  • The key happens to expire exactly between the calls to backendIncAndGetUsage and backendExpireIn.
  • If that happens, the key expires and the request count is therefore effectively reset to 0. This effectively turns the sliding window strategy into a fixed window strategy if an attacker managed to get lucky and cause this to happen at the end of each window.
  • The particular request during which this happens will fail since trying to change the expiry time of a non-existent key will cause an exception.

In short, it is unlikely to be exploitable by a malicious user and in the worst case would still rate limit calls within a given window.

@qwbarch
Copy link

qwbarch commented Jan 16, 2023

Hi @qwbarch, sorry for the slight delay in getting back to you -- I somehow missed the notification for your reply here -- and sorry for not fixing this bug yet.

To answer your question, it somewhat depends on which rate limiting strategy you plan to use and how much you care about strict enforcement of the policies. Generally speaking, I'd think that the library is safe to use until this is fixed.

For the fixed window strategy, the race condition doesn't matter, because it will only call backendIncAndGetUsage once initially.

For the sliding window strategy, the race conditions comes into play if:

  • The key happens to expire exactly between the calls to backendIncAndGetUsage and backendExpireIn.
  • If that happens, the key expires and the request count is therefore effectively reset to 0. This effectively turns the sliding window strategy into a fixed window strategy if an attacker managed to get lucky and cause this to happen at the end of each window.
  • The particular request during which this happens will fail since trying to change the expiry time of a non-existent key will cause an exception.

In short, it is unlikely to be exploitable by a malicious user and in the worst case would still rate limit calls within a given window.

Doesn't seem too bad to stick with the sliding window strategy then. Thanks a lot for the detailed reply!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants