Setki nieudanych zamówień w WooCommerce: atak card testing i jak go zatrzymać
- Typowe objawy
- Dziesiątki lub setki zamówień ze statusem Nieudane, kwoty po kilka złotych, losowe nazwiska
- Najczęstsza przyczyna
- Bot sprawdza skradzione karty przez Twoją kasę, zwykle bez włamania
- Czas naprawy
- Zatrzymanie: godzina lub dwie. Sprzątanie i zabezpieczenie: 1–2 dni
- Czy zrobisz to sam?
- Częściowo tak: ustawienia w panelu tak, reguły serwera i analiza logów raczej z pomocą
Szybka odpowiedź
Setki nieudanych zamówień po kilka złotych w krótkim czasie to prawie zawsze card testing: bot sprawdza przez Twoją kasę, które skradzione karty działają. Najpierw zatrzymaj atak (limit żądań na serwerze lub w Cloudflare, funkcja Limit prób zamówienia (Rate limit Checkout) dla kasy blokowej, CAPTCHA sprawdzana po stronie serwera), potem zgłoś go operatorowi płatności i zwróć pieniądze za transakcje, które przeszły. Sprzątaj dopiero po kopii bazy, a na koniec ustaw automatyczne usuwanie nieudanych zamówień.
Card testing (po polsku czasem „testowanie kart”) to sprawdzanie, czy numery kart kupione na czarnym rynku nadal działają. Przestępca nie robi tego w swoim sklepie, tylko w Twoim: automat wkłada do koszyka najtańszy produkt, wpisuje losowe dane i próbuje zapłacić kolejnymi kartami. Każda karta, która przejdzie, trafia potem do drogich zakupów albo na sprzedaż.
Dla Ciebie oznacza to zalew fałszywych zamówień, obciążony serwer i kłopoty z operatorem płatności. Ten poradnik prowadzi przez cztery etapy w kolejności, która ma znaczenie: zatrzymać, zgłosić, posprzątać, zabezpieczyć. Stan na listopad 2026, WooCommerce 11.2.
Po czym poznać atak card testing
Wejdź w WooCommerce → Zamówienia i kliknij filtr Nieudane (w wersji angielskiej Orders, Failed), czyli zamówienia, za które płatność się nie powiodła. Atak wygląda zwykle tak jak na zrzucie poniżej.

Typowe sygnały:
- Wiele zamówień w krótkim czasie, często w nocy, ze statusem Nieudane albo Oczekujące na płatność (w wersji angielskiej Failed i Pending payment).
- Małe, powtarzalne kwoty i ten sam tani produkt: próbka, naklejka, darowizna, produkt „zapłać ile chcesz”.
- Losowe dane: nazwiska bez sensu, adresy e-mail w dziwnych domenach, kraj niepasujący do sklepu.
- Notatki przy zamówieniach o odrzuconej karcie, często z różnymi powodami odmowy.
- Skok w panelu operatora płatności: dużo nieudanych lub zablokowanych płatności i kilka udanych na drobne kwoty.
- Lawina maili „Failed order” do administratora.
Jest też wariant bez zamówień. Według dokumentacji WooCommerce, jeśli widzisz w panelu operatora próby, a w sklepie nie ma wielu nieudanych zamówień, atakujący może sprawdzać karty, dodając je do kont klientów (zapisane metody płatności w „Moim koncie”). Stripe opisuje to samo: karty testuje się zarówno płatnościami, jak i samym zapisaniem karty.
Co to znaczy dla Twojego sklepu
To nie są utracone zamówienia. Nikt z tych „klientów” nie chciał nic kupić. Problem leży gdzie indziej:
- Spory o płatność (chargeback). Część kart przejdzie. Prawdziwy właściciel karty zobaczy obciążenie i zgłosi oszustwo w banku. Każdy taki spór kosztuje opłatę i czas.
- Gorsza ocena u banków. Stripe ostrzega, że duża liczba odrzuceń sprawia, iż banki traktują sklep jako bardziej ryzykowny, więc częściej odrzucają też prawdziwych klientów, nawet po ataku.
- Opłaty. W zależności od umowy z operatorem możesz płacić za każdą autoryzację, także nieudaną.
- Obciążenie serwera. Każda próba to zamówienie w bazie, notatki, maile. Sklep na zwykłym hostingu potrafi od tego zwolnić albo przestać odpowiadać.
Etap 1: zatrzymaj atak teraz
Na początek sprawdź, jaką masz kasę, bo od tego zależy, które zabezpieczenie zadziała. Wejdź w WooCommerce → Status → Status systemu i przewiń do sekcji Strony WooCommerce (WooCommerce pages). Przy stronie kasy (Checkout) zobaczysz jedną z dwóch informacji:
- Contains the woocommerce/checkout block – masz kasę blokową. Zamówienia idą przez Store API, czyli interfejs, przez który przeglądarka rozmawia ze sklepem, pod adres
/wp-json/wc/store/v1/checkout. - Contains the [woocommerce_checkout] shortcode – masz kasę klasyczną. Zamówienia idą pod adres
/?wc-ajax=checkout.
Boty potrafią wysyłać żądania prosto pod adres Store API, nawet jeśli Twój sklep używa kasy klasycznej. Dlatego zabezpiecz oba adresy, nie tylko ten, którego używasz.
-
Ukryj tani produkt, którego używa bot
Sprawdź w zamówieniach, co jest w koszyku. Zwykle to jeden produkt za kilka złotych albo produkt z ceną wpisywaną przez klienta. Ustaw go tymczasowo jako prywatny (w edycji produktu, w polu widoczności) albo przenieś do szkicu. Dokumentacja WooCommerce poleca to wprost jako pierwszą pomoc.
-
Włącz funkcję Limit prób zamówienia (Rate limit Checkout)
Rate limiting to ograniczenie liczby prób w danym czasie z jednego adresu. W WooCommerce → Ustawienia → Zaawansowane → Funkcje zaznacz Limit prób zamówienia (w wersji angielskiej Settings → Advanced → Features, Rate limit Checkout) i zapisz zmiany.

- Chroni tylko Store API. Sprawdziłem w kodzie WooCommerce 11.2.1: limit działa dla żądań POST pod
/wc/store/v1/checkout. Kasy klasycznej (?wc-ajax=checkout) nie obejmuje. Dokumentacja dla deweloperów mówi to samo: ustawienie w panelu dotyczy kasy blokowej. - Uważaj na Cloudflare i inne pośredniki. Jeśli sklep stoi za CDN, a serwer nie odtwarza prawdziwego adresu klienta, wszyscy klienci mogą wyglądać jak kilka adresów pośrednika i wspólnie wyczerpać limit. Wtedy deweloper włącza obsługę proxy filtrem (poniżej, do wtyczki typu mu-plugin albo pliku
functions.phpmotywu potomnego). Nie włączaj jej bez pośrednika, bo nagłówki z adresem można podrobić.
// tylko za CDN/pośrednikiem: adres klienta z nagłówków
add_filter( 'woocommerce_store_api_rate_limit_options', function ( $options ) {
$options['proxy_support'] = true;
return $options;
} );
-
Dodaj limit na brzegu sieci
Brzeg sieci to miejsce przed Twoim serwerem: CDN, np. Cloudflare, albo zapora hostingu. Limit ustawiony tam odciąża serwer, bo zatrzymane żądania bota w ogóle nie docierają do WordPressa. W Cloudflare w planie bezpłatnym (stan na październik 2026) dostępna jest jedna reguła ograniczania żądań, liczona po adresie IP w oknie 10 sekund, a warunek może dotyczyć tylko ścieżki adresu. Obejmie więc
/wp-json/wc/store/v1/checkout, ale nie kasę klasyczną, bowc-ajax=checkoutto parametr zapytania, a nie ścieżka. Warunek na parametr zapytania Cloudflare udostępnia od planu Pro. Bez Cloudflare albo przy kasie klasycznej poproś hosting o limit dla tych adresów na serwerze. -
Włącz CAPTCHA sprawdzaną po stronie serwera
CAPTCHA to test „czy jesteś człowiekiem”, np. Cloudflare Turnstile albo Google reCAPTCHA. Liczy się weryfikacja na serwerze: samo okienko w przeglądarce bot ominie, wysyłając żądanie bezpośrednio. WooCommerce w grudniu 2024 opisał, że część wtyczek nie chroniła kasy blokowej ani Store API i wymagała poprawek, więc zaktualizuj wtyczkę i sprawdź w jej opisie, czy obsługuje kasę, której używasz.
-
Wyłącz na czas ataku maile o nieudanych zamówieniach
W WooCommerce → Ustawienia → E-maile są dwa maile Nieudane zamówienie (Failed order): do administratora i do klienta. Ten drugi, jeśli jest włączony, przy ataku idzie na losowe adresy, wraca jako niedoręczony i psuje reputację Twojej domeny pocztowej. Wejdź w Zarządzaj przy każdym z nich, odznacz włączenie i zapisz. Po ataku włącz je z powrotem.
-
Rozważ tymczasowe utrudnienia
Jeśli atak nie słabnie: wyłącz zakupy bez konta (WooCommerce → Ustawienia → Konta i prywatność, opcja zakupów bez konta, w wersji angielskiej Enable guest checkout), wyłącz zakładanie kont na stronie „Moje konto” i płatności zapisanymi kartami. W ostateczności wyłącz na kilka godzin płatność kartą i zostaw przelew lub BLIK. To kosztuje część sprzedaży, więc cofnij te zmiany, gdy tylko atak ustanie.
Etap 2: zgłoś atak operatorowi płatności
Operator płatności (Stripe, PayU, Przelewy24, Tpay i inni) widzi atak lepiej niż Ty, bo ma dane o kartach i bankach. Zgłoś go tego samego dnia przez panel lub pomoc techniczną operatora. Przygotuj:
- przedział czasu ataku i przybliżoną liczbę prób,
- numery przykładowych zamówień i kwoty,
- adresy IP z logów serwera (jak je wyciągnąć, piszę w etapie 3),
- informację, jakie zabezpieczenia już włączyłeś.
Przy okazji zrób trzy rzeczy, które zalecają zarówno WooCommerce, jak i Stripe:
- Zwróć pieniądze za próby, które przeszły. Zwrot zanim właściciel karty zgłosi oszustwo zmniejsza ryzyko sporu. WooCommerce zaznacza, że zwrot nie gwarantuje odzyskania opłat transakcyjnych, więc o opłaty zapytaj operatora.
- Poproś o zaostrzenie ochrony antyfraudowej. W Stripe działa to automatycznie przy zalecanych integracjach (płatności oznaczone jako Blocked by Stripe), a w planach z regułami Radar możesz ustawić własne reguły, np. limit prób z jednego adresu. U innych operatorów nazwy są inne, więc zapytaj, co oferują.
- Sprawdź, czy nie wyciekł klucz. Jeśli w panelu operatora widzisz dużo więcej prób niż zamówień w sklepie, atak może omijać WooCommerce. Wygeneruj nowe klucze API u operatora i wpisz je w ustawieniach bramki płatności.
Szczegóły od strony Stripe opisuje dokumentacja Protect yourself from card testing, a od strony sklepu poradnik WooCommerce How do I prevent and respond to card testing attacks?.
Etap 3: posprzątaj po kopii
Sprzątanie zaczynasz od zebrania dowodów, potem robisz kopię, a dopiero na końcu usuwasz.
Znajdź adresy i godziny ataku w logach
Log dostępu (access log) to plik, w którym serwer zapisuje każde żądanie. Pobierzesz go z panelu hostingu, zwykle z sekcji statystyk lub logów. Poniższe polecenie liczy, ile prób złożenia zamówienia przyszło z każdego adresu IP. Działa dla obu rodzajów kasy:
grep -E 'wc-ajax=checkout|wc/store(/v1)?/checkout' access.log \
| awk '{print $1}' | sort | uniq -c | sort -rn | head -20
A to rozkłada próby na minuty, co pokazuje, kiedy atak się zaczął i skończył:
grep -E 'wc-ajax=checkout|wc/store(/v1)?/checkout' access.log \
| awk '{print substr($4,2,17)}' | sort | uniq -c
Wynik pierwszego polecenia (liczba prób z każdego adresu IP) na przykładowym, spreparowanym logu z adresami z puli dokumentacyjnej (nie są to adresy prawdziwego ataku):
3 203.0.113.17
2 198.51.100.42
Bez terminala: otwórz log w edytorze tekstu i wyszukaj wc-ajax=checkout oraz store/v1/checkout. Przy dużym pliku lepiej poprosić o to hosting.
Wyeksportuj listę i zrób kopię bazy
Zanim cokolwiek usuniesz, zapisz listę nieudanych zamówień do pliku i zrób kopię bazy danych (w phpMyAdmin: eksport, albo kopia w panelu hostingu). WP-CLI, czyli narzędzie do obsługi WordPressa z terminala, zrobi obie rzeczy. Polecenia poniżej sprawdziłem na testowej instalacji; parametr --user to identyfikator administratora, w którego imieniu działa polecenie.
# kopia całej bazy danych do pliku
wp db export przed-sprzataniem-$(date +%F).sql
# ile jest nieudanych zamówień (tylko odczyt)
wp wc shop_order list --status=failed --format=count --user=1
# lista do pliku CSV: numer, kwota, data, dane rozliczeniowe
wp wc shop_order list --status=failed --after=2026-11-01T00:00:00 \
--fields=id,total,date_created,billing --per_page=100 \
--format=csv --user=1 > nieudane.csv
Prawdziwy wynik na instalacji testowej (fragment, dane fikcyjne):
$ wp wc shop_order list --status=failed --format=count --user=1
28
$ wp wc shop_order list --status=failed \
--fields=id,status,total,date_created --per_page=3 --user=1
id status total date_created
42 failed 5.00 2026-10-16T07:25:31
41 failed 5.00 2026-10-16T07:25:30
40 failed 5.00 2026-10-16T07:25:29
Polecenie wp wc korzysta z interfejsu WooCommerce, więc działa tak samo przy starym zapisie zamówień w tabeli wpisów i przy nowym, osobnym (HPOS). Zwraca najwyżej 100 zamówień naraz; przy większej liczbie dodaj --page=2, --page=3 i tak dalej.
Przenieś do kosza, a potem usuń
W panelu: Zamówienia → filtr Nieudane, zaznacz wszystkie na stronie, z listy Działania masowe wybierz Przenieś do kosza i kliknij Zastosuj. Liczbę zamówień na stronie zwiększysz w Opcjach ekranu u góry ekranu. Kosz daje Ci możliwość cofnięcia.
W WP-CLI: najpierw przejrzyj listę numerów, potem przenieś je do kosza. Zawęź daty do czasu ataku, żeby nie ruszyć prawdziwych nieudanych płatności sprzed niego. WP-CLI nie ma tu trybu próbnego, dlatego pierwsze polecenie pełni jego rolę: pokazuje dokładnie to, co drugie zmieni.
# 1. podgląd: które zamówienia zostaną ruszone
wp wc shop_order list --status=failed \
--after=2026-11-01T00:00:00 --before=2026-11-02T12:00:00 \
--field=id --per_page=100 --user=1
# 2. przeniesienie tych samych zamówień do kosza
wp wc shop_order list --status=failed \
--after=2026-11-01T00:00:00 --before=2026-11-02T12:00:00 \
--field=id --per_page=100 --user=1 \
| xargs -r -n1 wp wc shop_order delete --user=1
Bez parametru --force=true zamówienie trafia do kosza. Na kopii testowego zamówienia wygląda to tak:
$ wp wc shop_order delete 49 --user=1
Success: Trashed shop_order 49
$ wp wc shop_order delete 49 --force=true --user=1
Success: Deleted shop_order 49.
Trwałe usunięcie z --force=true zostaw na koniec, gdy sprawdzisz, że raporty sprzedaży i prawdziwe zamówienia są w porządku. Przy okazji przejrzyj Użytkownicy → filtr Klient, posortuj po dacie rejestracji i sprawdź konta założone w czasie ataku. Usuń je dopiero po przejrzeniu, bo wśród nich mogą być prawdziwi klienci.
Etap 4: zabezpiecz sklep na stałe
Po ataku boty często wracają, tylko wolniej. Ustaw rzeczy, które ograniczą skutki następnej próby.
Automatyczne usuwanie nieudanych zamówień
W WooCommerce → Ustawienia → Konta i prywatność, w sekcji Zachowywanie danych osobowych, ustaw, po jakim czasie sklep sam przenosi do kosza zamówienia nieudane (Zachowaj nieudane zamówienia) i oczekujące na płatność (Zachowaj wstrzymane zamówienia; w wersji angielskiej Retain failed orders i Retain pending orders). Według dokumentacji WooCommerce sprzątanie działa raz dziennie, a puste pole oznacza przechowywanie bez końca.

Sklep nie usuwa tu zamówień od razu, tylko przenosi je do kosza. Zamówień zrealizowanych (Retain completed orders) nie ruszaj bez rozmowy z księgową: tam WooCommerce anonimizuje dane, a dokumenty sprzedaży mają swoje terminy przechowywania.
Pozostałe zabezpieczenia
| Zabezpieczenie | Co daje | Gdzie |
|---|---|---|
| Stały limit na brzegu sieci | Zatrzymuje boty, zanim obciążą serwer | Cloudflare lub hosting |
| Rate limit Checkout włączony na stałe | Limit prób w kasie blokowej | Ustawienia → Zaawansowane → Funkcje |
| CAPTCHA z weryfikacją na serwerze | Odcina proste skrypty | Wtyczka, aktualna wersja |
| Brak produktów „zapłać ile chcesz” bez minimum | Bot nie testuje kart za 1 zł | Edycja produktu |
| Zakładanie kont tylko po zakupie | Trudniej testować karty przez zapisane metody płatności | Ustawienia → Konta i prywatność |
| Aktualna wtyczka bramki płatności | Najnowsze zabezpieczenia operatora | Wtyczki |
| Alarm przy skoku nieudanych płatności | Dowiadujesz się po godzinie, nie po tygodniu | Panel operatora, monitoring |
Jeśli w ustawieniach kont masz włączone zakładanie konta na stronie „Moje konto” (On "My account" page), a nie potrzebujesz go, wyłącz je. Konto po zakupie (After checkout) jest dla prawdziwych klientów wygodniejsze i trudniejsze do nadużycia.
Przed okresem wzmożonej sprzedaży, kiedy boty są szczególnie aktywne, przejdź też listę kontrolną sklepu na Black Friday. Jeśli obok card testingu serwer obciążają też inne automaty, zajrzyj do poradnika Boty AI przeciążają stronę.
Właściciel sklepu z akcesoriami budzi się z kilkuset mailami „Failed order”. W nocy ktoś złożył kilkaset zamówień na naklejkę za 4 zł, a w panelu operatora widać też kilkanaście udanych płatności. Sklep ma kasę klasyczną, więc samo włączenie Rate limit Checkout nic nie zmienia. Atak ustaje dopiero po dodaniu przez hosting limitu żądań dla obu adresów kasy i ukryciu naklejki. Udane płatności zostają zwrócone tego samego dnia, a zgłoszenie do operatora zawiera listę adresów IP z logu. Nieudane zamówienia trafiają do kosza dopiero następnego dnia, po eksporcie i kopii bazy.
Kiedy nie robić tego samemu
Ustawienia w panelu WooCommerce zmienisz sam. Pomoc przyda się, gdy:
- atak trwa mimo włączonych zabezpieczeń albo sklep przestaje odpowiadać,
- trzeba ustawić reguły na serwerze lub w Cloudflare i nie chcesz zablokować prawdziwych klientów,
- w panelu operatora widać próby, których nie ma w sklepie (możliwy wyciek klucza),
- zamówień jest tyle, że sprzątanie w panelu trwałoby godzinami,
- pojawiły się nowe konta administratorów albo obce pliki, czyli coś więcej niż card testing (zobacz jak sprawdzić, czy strona została zhakowana).
Atak trwa teraz?
Zatrzymuję card testing w sklepach WooCommerce: reguły na serwerze i w Cloudflare, ustawienia kasy, CAPTCHA, analiza logów do zgłoszenia operatorowi i bezpieczne sprzątanie zamówień. Szybka Interwencja: 299 zł netto, 7 dni gwarancji na naprawę.
Najczęstsze pytania
Czy atak card testing oznacza, że ktoś włamał się do mojego sklepu?
Zwykle nie. Atakujący korzysta z Twojej kasy tak jak zwykły klient, tylko robi to automatem i tysiące razy. Nie potrzebuje do tego hasła do panelu. Warto jednak sprawdzić klucze operatora płatności i listę administratorów, bo wyciek klucza tajnego pozwala testować karty z pominięciem sklepu.
Czy nieudane zamówienia z ataku to utracona sprzedaż?
Nie. To nie są prawdziwi klienci, którym nie udało się zapłacić, tylko próby sprawdzenia skradzionych kart. Problemem są skutki uboczne: obciążenie serwera, opłaty za autoryzacje, ryzyko sporów o płatność i gorsza ocena sklepu u banków.
Czy mogę po prostu usunąć wszystkie nieudane zamówienia?
Tak, ale dopiero po zgłoszeniu ataku operatorowi płatności, po wyeksportowaniu listy zamówień i po kopii bazy danych. Najpierw przenieś je do kosza, a usuwaj na stałe dopiero, gdy wiesz, że nic potrzebnego nie zniknęło.
Czy włączenie Rate limit Checkout wystarczy?
Nie zawsze. Według kodu WooCommerce 11.2 ta funkcja ogranicza tylko wysyłanie zamówień przez Store API, czyli kasę blokową. Kasa klasyczna, oparta na shortcode, wymaga ograniczenia na poziomie serwera lub CDN i CAPTCHA sprawdzanej po stronie serwera.
Czy wyłączenie zakupów bez konta zatrzyma atak?
Utrudni go, bo bot musi najpierw założyć konto, ale odbije się też na prawdziwych klientach. Traktuj to jako środek na czas ataku, nie stałe ustawienie, i połącz go z wyłączeniem zakładania kont bez weryfikacji.