Is your faceted search under siege? Now you have a shield.
Distributed bots and AI crawlers generate millions of unique combinations on the parameter ?q=, saturating CPUs and databases without any single IP exceeding a reasonable threshold. Faceted Search Rate Limiter blocks these attacks with two independent layers of defense, without affecting the real traffic of your customers.
The problem
Every unique combination of ?q= that does not match the cache of ps_facetedsearch generates a complete chain of queries on ps_product, ps_layered_price_index, and related tables. Distributed botnets and scrapers for training AI models can produce millions of variants in just a few days, saturating the server while remaining invisible to traditional rate limiting systems based on single IPs.
Two independent layers of defense
Layer 1 — Bot fingerprinting
Every HTTP signal contributes to a score. The request is blocked when the total reaches the configurable threshold (default: 4). Effective against distributed botnets where no IP exceeds classic limits.
| Signal | Score |
|---|---|
| Protocol HTTP/1.0 | 4 |
| Absent User-Agent | 3 |
| No cookie PrestaShop-* | 2 |
| Absent Referer | 1 |
The detection of HTTP/1.0 automatically disables in the presence of reverse-proxy headers (X-Forwarded-For, CF-Connecting-IP, etc.) to avoid false positives on Nginx, Apache, and Cloudflare.
Layer 2 — Rate limiting per IP
Counts the requests ?q= per IP in a fixed time window (default: 30 req / 60 s). Uses APCu with atomic increment when available; in absence, it falls back to a file counter in var/cache/ with flock to ensure atomicity.
Counter files are automatically rotated: about 1% of requests trigger a cleanup that removes files older than window × 3 seconds. The Clear log button in the back office immediately resets all counters — useful for restoring normal access after an attack.
Normalization of the parameter ?q=
Filter tokens within ?q= are sorted alphabetically before ps_facetedsearch calculates its MD5 cache key. This collapses variants by permutation (Brand-Nike/Color-Red and Color-Red/Brand-Nike) into the same cache entry, drastically reducing cache misses caused by enumeration attacks.
Bot score threshold — recommended presets
A request is blocked when the total score is ≥ threshold. The default threshold 4 allows visitors coming from direct links; lowering it to 3 is recommended during active attacks.
| Signal combinations | Score | T=3 | T=4 | T=5 |
|---|---|---|---|---|
| Only no Referer | 1 | — | — | — |
| Only no cookie | 2 | — | — | — |
| Only no User-Agent | 3 | 🚫 | — | — |
| No cookie + no Referer | 3 | 🚫 | — | — |
| Only HTTP/1.0 | 4 | 🚫 | 🚫 | — |
| No User-Agent + no Referer | 4 | 🚫 | 🚫 | — |
| No cookie + no User-Agent | 5 | 🚫 | 🚫 | 🚫 |
Logs and response to blocks
Log file
Every block is queued in var/logs/tec_facetlimit.log with tab-separated columns: timestamp, type (BOT / RATELIMIT), IP, detected signals, URI, and User-Agent. The log is viewable and can be cleared directly from the configuration page in the back office.
Response to blocked client
AJAX calls from ps_facetedsearch receive a HTTP 429 Too Many Requests with JSON body {"error":"rate_limited"} and Retry-After header. Direct browser navigation receives a readable HTML page with a friendly message and a link back to the category — no raw JSON exposed to the real user.
Requirements
| Component | Version / notes |
|---|---|
| PrestaShop | 1.7 – 9.x |
| PHP | 8.1+ |
| APCu | Optional — recommended for maximum accuracy of the rate limiter; in absence, the module uses file counters |
Installation
- Upload the folder tec_facetlimit to
/modules/ - Go to Back Office → Modules → Module Manager, search for Faceted Search Rate Limiter and click Install