The Store API Now Supports Rate Limiting

Popular stores can become the targets of malicious actors. One example of known abusive patterns is making many requests in a very short timeframe to try to overwhelm the store.

To counter such situations, the Store API now provides a rate limiting function — starting with WooCommerce Blocks 8.9.0, released on November 8th. When enabled, it will protect the block-based checkout process and all requests to the /cart and /product endpoints. This feature will land in WooCommerce 7.2 on December 13th, 2022.

Rate limiting is opt-in and is intended for advanced merchants and platforms.

Enabling Rate Limiting

Developers can enable rate limiting using the woocommerce_store_api_rate_limit_options filter. Limiting is based on user ID for registered users and IP address for guest users.

add_filter( 'woocommerce_store_api_rate_limit_options', function() {
    return [
        'enabled' => true, // enables/disables Rate Limiting. Default: false
        'proxy_support' => false, //enables/disables Proxy support. Default:false
        'limit' => 25, // limit of request per timeframe. Default: 25
        'seconds' => 10, // timeframe in seconds. Default: 10
} );

With this configuration, the Store API will block requests from a user ID or IP address if they’ve sent 25 requests or more within 10 seconds or less. The limit will be reset once the timeframe has expired.

Those defaults — 25 requests and 10 seconds — can be adjusted in the filter.

Supporting Proxies and Load Balancers

Like any mechanism that restricts usage to counter potential abuse of an API, this is a sensitive feature that should be used carefully.

In a scenario where a store is behind another service layer (a proxy, load balancer, etc.), the developer should enable standard proxy support through the woocommerce_store_api_rate_limit_options filter. Otherwise rate limiting might be wrongly triggered and group-limit requests.

For the proxy_support option to work properly, service layers must be passing the originating IP through standard IP forwarding headers, namely:

  • X_REAL_IP | CLIENT_IP: Custom popular implementations that simplify obtaining the origin IP for the request.
  • X_FORWARDED_FOR: The de-facto standard header for identifying the originating IP, see documentation here.
  • X_FORWARDED: Documentation hereRFC 7239.

Tracking Abuses

Developers can use the woocommerce_store_api_rate_limit_exceeded action to track and handle instances of API abuse:

    function ( $offending_ip ) { /* Custom tracking implementation */ }

For a more in-depth description of this feature, please take a look at the complete documentation here.

We welcome suggestions and issues in the WooCommerce Blocks repository on GitHub, so don’t miss out on the chance to help us improve this!

11 responses to “The Store API Now Supports Rate Limiting”

  1. I’m not a developer so excuse my ignorance. I’ve been hit with card testing scam orders a few times and would like to implement this. I just updated to 7.2, where would I add this code? Thanks.

    1. Paulo Arromba Avatar
      Paulo Arromba

      Hi @silentkv,
      I created a simple plugin to enable this feature, which you can download here.
      I advise caution enabling this since this is a feature that has the potential to break a website, depending on how it is hosted, so be sure to test everything thoroughly 😉

      1. I’m using the Simple Cloudflare Turnstile on my E-commerce sites to prevent card testing on checkout. Is it worth using this as an additional security layer?

        1. Paulo Arromba Avatar
          Paulo Arromba

          Hi @Migzy, I believe it only supports the shortcode version of checkout by looking at that plugin description, and this rate-limiting feature applies to the Checkout Block.

    2. stephenfeather Avatar

      Been there, got a black mark on our merchant account because of it despite issuing refunds as soon as discovered.

      We use a FingerprintJS an implementation to store a fingerprint with each order now.

      Additionally, we use FraudLabs Pro to get back rating scores about IPs, emails, addresses. If triggered, orders are placed in a security review status. We are not passing CC information through FraudLabs as that would break our PCI compliance.

      When bad orders are confirmed, refunds issued immediately and a report is sent to our merchant processor with full details about the visitor.

      Knock on wood, this multiprong approach has been working. Visa and MasterCard don’t care nor do the banks. Got to protect ourselves. Good luck.

  2. Can we use the RateLimits class for custom REST API endpoints too?

    1. Paulo Arromba Avatar
      Paulo Arromba

      Hi @alev,
      Since this is being shipped as part of core, the self-contained RateLimits utility class can be imported and reused in custom implementations outside the Store API scope. Unfortunately, we can’t offer support for said implementation.
      Please note that this class is namespaced under StoreAPI, so extending or using WC_Rate_Limiter directly might make more sense, considering you’re referring to custom WooCommerce REST API endpoints.

  3. I notice it specifies the block checkout. Will this also work if using the shortcode to configure the checkout page? I’ve got a lot of clients that hate the Gutenberg editor…

    1. Paulo Arromba Avatar
      Paulo Arromba

      Hi @bigcloudmedia, no, this Rate Limiting feature only applies to Store API, which is not used by the shortcode versions of cart/checkout. If you or your clients want to test this rate-limiting protection feature on checkout, using the block version is the only way.

      Why not set up a separate example page and try to insert and configure the Checkout block to have a look alongside the shortcode version?
      I find it a straightforward use case to test with the Gutenberg editor, and we sure would like to hear some feedback on how to improve it 😀

  4. Hi @silentkv,

    shouldn’t the code snippet above be:

    add_filter( ‘woocommerce_store_api_rate_limit_options’, function() {
        return [
            ‘enabled’ => true, // enables/disables Rate Limiting. Default: false
            ‘proxy_support’ => false, //enables/disables Proxy support. Default:false
            ‘limit’ => 25, // limit of request per timeframe. Default: 25
            ‘seconds’ => 10, // timeframe in seconds. Default: 10
    } );

    This is a very useful feature. Thank you for taking the time to do it.

    1. Paulo Arromba Avatar
      Paulo Arromba

      Hi @alanhawtin, thanks for the heads up. I updated the code snippet 👍

Leave a Reply

Your email address will not be published. Required fields are marked *