feat: rate limit checkout attempts #3678
Open
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
All Submissions:
Changes proposed in this Pull Request:
Adds support for rate limiting checkout attempts by user. If a
NEWSPACK_CHECKOUT_RATE_LIMIT
environment constant is defined as an integer, checkout attempts that occur within that number of seconds of a prior checkout attempt by the same user (if logged in) or IP (if not logged in) will be rejected before WooCommerce sends payment info to any payment gateways.If WooCommerce detects any other checkout validation errors that would prevent the checkout from occurring (such as missing required fields), we won't count this as a checkout attempt, so that readers can attempt successive checkouts in order to correct errors without being rate limited. So in practice, only successful transactions and checkout requests which would result in declined payments should be rate-limited.
The mechanism used is transients: when a checkout request is submitted and has no validation errors, a transient named with the hashed user ID or IP with a value of the UNIX timestamp of the request is created with an expiration time matching
NEWSPACK_CHECKOUT_RATE_LIMIT
number of seconds (unlessNEWSPACK_CHECKOUT_RATE_LIMIT
is 0, which is functionally be the same as not defining the constant). If another checkout request is submitted and the transient both exists and is withinNEWSPACK_CHECKOUT_RATE_LIMIT
number of seconds of the new request, the transient value and expiration are updated and the request is rejected.Also adds rate-limiting for adding new payment methods in My Account, but because of how this feature is split between the main WooCommerce plugin and many payment gateway extension plugins, it doesn't necessarily rate limit declined payment methods (thus still allowing for card testing with some payment gateways). This will need to be handled in a separate PR, possibly via JS since each payment method behaves differently when deciding when/whether to contact the payment processor.
How to test the changes in this Pull Request:
wp-config.php
, defineNEWSPACK_CHECKOUT_RATE_LIMIT
as something long enough for manual testing like60
or90
.Please wait a moment before trying to complete this transaction again
.Testing rate-limiting of adding new payment methods
/my-account/add-payment-method
since this URL isn't blocked even if the menu item is hidden).Please wait a moment before trying to add a new payment method
error message. (Note that the error message may flash and disappear after a moment, but this seems to be a Woo/My Account bug and isn't related to the changes in this PR.)Other information: