Il lunedì mattina l’elenco degli ordini di WooCommerce è pieno: centinaia di ordini falliti arrivati durante la notte, tutti per lo stesso prodotto da pochi euro, con nomi improbabili e indirizzi email senza senso. Qualcuno è andato a buon fine. Poche ore dopo arriva un’email dal fornitore dei pagamenti che segnala un aumento anomalo di transazioni rifiutate. Il sito non mostra script estranei, i file sono puliti, eppure il negozio è sotto attacco.
Nel carding il negozio non è il bersaglio ma lo strumento: serve a qualcun altro per scoprire quali carte rubate funzionano ancora. Il conto però lo paga il negozio.
È il card testing, o carding: l’uso automatizzato del checkout di un e-commerce per verificare numeri di carta rubati. In questo articolo vediamo come riconoscerlo, come distinguerlo da un’infezione vera e propria, quali endpoint di WooCommerce vengono usati, quali difese offrono WooCommerce, il web server e il gateway di pagamento, e come ripulire ordini e clienti falsi senza cancellare anche le tracce che servono.
Cos’è il card testing
Chi compra dati di carte di pagamento rubati, da un skimmer, da una violazione di dati o da un elenco generato per enumerazione, non sa quali siano ancora validi. Per scoprirlo prova a usarle con piccoli pagamenti su negozi qualsiasi: se la transazione passa, la carta è buona e può essere usata per acquisti più consistenti o rivenduta a un prezzo maggiore. La documentazione di Stripe sul card testing descrive esattamente questo schema: script che provano grandi quantità di carte, raccolgono le risposte delle banche emittenti e conservano quelle valide.
Un negozio WooCommerce è un bersaglio comodo per diverse ragioni: il checkout come ospite non richiede registrazione, i prodotti a basso prezzo o le donazioni di importo libero consentono addebiti minimi, e l’interfaccia è standard, quindi uno script scritto per un negozio funziona su migliaia di altri. Il negozio non viene scelto per quello che vende: viene scelto perché risponde.
Le conseguenze però sono concrete. Le transazioni riuscite con carte rubate diventano contestazioni e rimborsi, spesso con le commissioni a carico del negozio; il tasso di rifiuto alto peggiora la reputazione dell’esercente presso le banche, che iniziano a rifiutare anche pagamenti legittimi; e nei casi più gravi il fornitore dei pagamenti può sospendere l’account. A tutto questo si aggiunge il carico sul server, perché ogni tentativo è una richiesta dinamica che attraversa l’intero stack di WordPress.
I sintomi da riconoscere
Il card testing ha un aspetto piuttosto riconoscibile, soprattutto se si guardano gli ordini tutti insieme invece che uno alla volta:
- molti ordini con stato Non riuscito o In attesa di pagamento in un intervallo breve, spesso di notte;
- lo stesso prodotto, di solito il più economico, o lo stesso importo ripetuto;
- nomi e indirizzi email generati a caso, indirizzi di fatturazione incoerenti con il paese della carta;
- nelle note dell’ordine, una serie di messaggi del gateway con codici di rifiuto generici, carta non valida o fondi insufficienti;
- avvisi del fornitore dei pagamenti, preavvisi di frode e, nelle settimane successive, contestazioni sugli ordini andati a buon fine;
- se la registrazione al checkout è attiva, decine di nuovi account cliente mai usati.
Un’ondata di ordini falsi non è sempre card testing. Ordini con bonifico o contrassegno che restano in attesa, senza tentativi di pagamento, sono di solito spam o sabotaggio; ordini che esauriscono le scorte senza pagare mirano al magazzino. La distinzione conta perché le contromisure sono in parte diverse, ma i primi passi, cioè capire quale endpoint viene usato e da chi, restano gli stessi.
Carding o skimmer?
Un negozio che riceve segnalazioni di frodi con le carte deve porsi subito una domanda: le carte arrivano da fuori, o sono state rubate qui? Nel card testing i numeri sono già in mano all’attaccante e il negozio fa solo da banco di prova: gli ordini sono falsi, i clienti non esistono, e le carte appartengono a persone che non hanno mai visitato il sito. In un’infezione da skimmer succede il contrario: gli ordini sono veri, i clienti sono reali, e le frodi compaiono giorni o settimane dopo sulle carte di chi ha comprato davvero.
Il carding non richiede alcuna compromissione del sito e non modifica file né database, a parte gli ordini che crea. Uno skimmer invece è codice malevolo inserito nel negozio, e per trovarlo servono gli strumenti descritti nell’articolo sugli skimmer JavaScript nel checkout. Le due cose possono anche coesistere: un negozio con uno skimmer attivo espone i dati dei propri clienti, e quei numeri finiscono prima o poi negli stessi elenchi che qualcuno proverà su altri negozi. Se le segnalazioni riguardano clienti veri, va cercata un’infezione prima di occuparsi dei bot.
Gli endpoint presi di mira
Un bot di card testing non compila il modulo del checkout come farebbe una persona: invia direttamente le richieste che il modulo produrrebbe. In WooCommerce le porte d’ingresso principali sono tre. Il checkout classico, quello dello shortcode, invia l’ordine con una richiesta POST a /?wc-ajax=checkout. Il blocco Checkout usa invece la Store API, un’interfaccia REST pubblica pensata per i frontend, con l’endpoint /wp-json/wc/store/v1/checkout. Infine, la pagina Aggiungi metodo di pagamento dell’area account permette di salvare una carta senza acquistare nulla, e la documentazione di Stripe ricorda che le verifiche fatte in fase di configurazione della carta sono particolarmente appetibili, perché di solito non compaiono nell’estratto conto del titolare.
La Store API è comoda per i bot perché è documentata e prevedibile: si aggiunge un prodotto al carrello, si invia il checkout, si legge la risposta in JSON. Il nonce richiesto per le operazioni di scrittura non è un ostacolo, perché qualsiasi client lo ottiene dalla risposta a una semplice richiesta del carrello. Il primo passo è quindi capire, dai log di accesso, quale di queste strade viene usata e da quanti indirizzi:
LOG=/var/log/nginx/access.log
FILTRO='POST /(\?wc-ajax=checkout|wp-json/wc/store(/v1)?/checkout|\?rest_route=/wc/store)'
# Indirizzi IP con più tentativi di checkout
grep -E "$FILTRO" "$LOG" | awk '{print $1}' | sort | uniq -c | sort -rn | head -20
# User agent più frequenti sulle stesse richieste
grep -E "$FILTRO" "$LOG" | awk -F'"' '{print $6}' | sort | uniq -c | sort -rn | head -10
# Tentativi al minuto: un picco regolare è la firma di uno script
grep -E "$FILTRO" "$LOG" | awk '{print substr($4, 2, 17)}' | uniq -c | tail -30
Gli attacchi più rozzi arrivano da pochi indirizzi con user agent vistosi, come python-requests o curl, o con un user agent da browser identico per migliaia di richieste. Quelli più curati ruotano gli indirizzi attraverso proxy residenziali e variano l’user agent, e allora il segnale diventa la cadenza: richieste di checkout senza le visite alle pagine di prodotto e al carrello che un cliente vero farebbe prima. Nell’articolo sui log di accesso di Apache, NGINX e LiteSpeed trovi come leggere questi file anche su configurazioni diverse.
Le difese integrate in WooCommerce
WooCommerce include un sistema di rate limiting per la Store API, ma, come spiega la documentazione per sviluppatori, è disattivato per impostazione predefinita. Dalla versione 9.6 si può attivare una limitazione più severa sul solo checkout direttamente dal pannello, in WooCommerce → Impostazioni → Avanzate → Funzionalità, con la voce dedicata al rate limiting del blocco Checkout e della Store API: si applica all’invio dell’ordine e consente al massimo tre richieste ogni 60 secondi. Per il resto della Store API il limite si configura con un filtro, per esempio in un plugin must-use:
<?php
// wp-content/mu-plugins/store-api-rate-limit.php
add_filter(
'woocommerce_store_api_rate_limit_options',
function () {
return array(
'enabled' => true,
'proxy_support' => false, // true solo dietro una CDN o un proxy che imposta X-Forwarded-For
'limit' => 25, // richieste consentite…
'seconds' => 10, // …in questa finestra
);
}
);
Due dettagli contano. Il limite si calcola per utente collegato o per indirizzo IP, e dietro una CDN tutti i visitatori sembrano arrivare dagli indirizzi della CDN: per questo esiste proxy_support, che però va attivato solo se il sito è davvero dietro un proxy affidabile, altrimenti un bot può scrivere l’intestazione X-Forwarded-For che preferisce e cambiare indirizzo a ogni richiesta. E il limite per IP serve poco contro gli attacchi che ruotano gli indirizzi: lo ammette lo stesso team di WooCommerce in un articolo dedicato al card testing, che dalla versione 9.8 introduce il filtro woocommerce_store_api_rate_limit_id per basare il limite su un’impronta diversa dall’indirizzo.
Lo stesso articolo indica il secondo strumento, il CAPTCHA, con un’avvertenza: diversi plugin di CAPTCHA proteggevano il modulo classico ma non la Store API, e un bot che usa l’API li aggirava senza accorgersene. Quando si sceglie un plugin, va verificato che protegga esplicitamente il blocco Checkout. Completano il quadro le misure suggerite nella guida di WooCommerce al card testing: disattivare il checkout come ospite durante un attacco, togliere o nascondere i prodotti a prezzo molto basso e le donazioni a importo libero, limitare il salvataggio delle carte nell’area account.
Rate limiting e regole sul web server
Le difese dentro WooCommerce hanno un limite strutturale: ogni richiesta, anche quella che verrà respinta, carica WordPress, i plugin e il database. Durante un attacco intenso conviene fermare le richieste prima, sul web server, dove costano quasi nulla. Con NGINX si può applicare un limite di frequenza solo alle richieste di checkout, lasciando libero il resto del sito:
# Blocco http {}: la chiave è vuota per tutte le richieste che non sono checkout,
# e le richieste con chiave vuota non vengono conteggiate
map $request_method $rmw_post {
POST 1;
default 0;
}
map "$rmw_post$request_uri" $rmw_checkout {
default "";
"~^1/wp-json/wc/store(/v1)?/checkout" $binary_remote_addr;
"~^1/\?rest_route=(/|%2F)wc(/|%2F)store" $binary_remote_addr;
"~^1/.*[?&]wc-ajax=checkout" $binary_remote_addr;
"~^1/[^?]*/add-payment-method" $binary_remote_addr;
}
limit_req_zone $rmw_checkout zone=checkout:10m rate=6r/m;
# Blocco server {} del negozio
limit_req zone=checkout burst=3 nodelay;
limit_req_status 429;
Sei tentativi al minuto per indirizzo, con una piccola tolleranza, sono più che sufficienti per un cliente che sbaglia il numero della carta due volte. Il percorso della pagina per aggiungere un metodo di pagamento dipende dalla lingua e dalle impostazioni dell’area account, quindi va adattato al negozio. Su Apache e LiteSpeed lo stesso risultato si ottiene con regole ModSecurity o con i limiti di connessione del server, e fail2ban può leggere il log e bloccare nel firewall gli indirizzi che superano una soglia.
Contro gli attacchi distribuiti su migliaia di indirizzi il livello più efficace è ancora più a monte: una CDN o un WAF con gestione dei bot, che può presentare una verifica solo sulle pagine di checkout o solo al traffico con reputazione dubbia. In emergenza, anche una regola che blocca temporaneamente la Store API di checkout, se il negozio usa il checkout classico e non ne ha bisogno, chiude una porta intera.
Le protezioni del gateway di pagamento
Il gateway vede tutte le transazioni del negozio e, per i fornitori più grandi, quelle di moltissimi altri esercenti: è nella posizione migliore per riconoscere una carta che viene provata ovunque. Stripe, per esempio, descrive nella documentazione citata controlli automatici contro il card testing, tra cui limiti di frequenza, modelli di rilevamento e CAPTCHA attivati quando riconosce un attacco, a patto di usare le integrazioni consigliate e di trasmettere dati come indirizzo IP, email e indirizzo di fatturazione. Con Radar si possono poi aggiungere regole personalizzate, comprese quelle sulla velocità, se il piano le prevede: per esempio bloccare più di un certo numero di carte diverse dallo stesso indirizzo in un’ora. Anche WooPayments, PayPal e gli altri fornitori offrono strumenti antifrode analoghi, da configurare nel pannello del gateway.
C’è poi un aspetto che collega il card testing alla sicurezza del sito. Le chiavi API del gateway sono salvate nelle impostazioni del plugin, nel database. Se il sito è stato compromesso, anche mesi prima, la chiave segreta può essere finita nelle mani sbagliate, e con quella un attaccante crea pagamenti direttamente sull’API del fornitore, senza passare dal negozio e quindi senza lasciare traccia nei log del sito. Se gli avvisi del gateway non trovano riscontro negli ordini di WooCommerce, la prima cosa da fare è ruotare le chiavi, e la seconda è capire da dove sono uscite.
Ripulire ordini e clienti falsi
Fermato l’attacco, restano centinaia di ordini e forse di account da togliere di mezzo. La tentazione di cancellare tutto in blocco va frenata: prima si rimborsano, dal pannello del gateway o da WooCommerce, i pagamenti andati a buon fine con carte rubate, come raccomanda la stessa guida di WooCommerce, per evitare che diventino contestazioni. Poi si esporta l’elenco degli ordini sospetti, che serve al fornitore dei pagamenti e a eventuali segnalazioni. Con WP-CLI si può estrarre un elenco da rivedere, indipendente da come sono salvati gli ordini:
<?php
// ordini-sospetti.php — eseguire con: wp eval-file ordini-sospetti.php > sospetti.tsv
$ids = wc_get_orders(
array(
'status' => array( 'failed', 'pending' ),
'date_created' => '>' . ( time() - 2 * DAY_IN_SECONDS ),
'limit' => -1,
'return' => 'ids',
)
);
foreach ( $ids as $id ) {
$o = wc_get_order( $id );
printf(
"%d\t%s\t%s\t%s\t%s\t%s\n",
$id,
$o->get_created_via(),
$o->get_customer_ip_address(),
$o->get_billing_email(),
$o->get_total(),
$o->get_customer_user_agent()
);
}
# Dopo aver controllato sospetti.tsv a mano: eliminare gli ordini elencati
cut -f1 sospetti.tsv | xargs -I{} wp wc shop_order delete {} --force=true --user=1
# Account cliente creati durante l'attacco, dal più recente
wp user list --role=customer --fields=ID,user_login,user_email,user_registered \
--orderby=registered --order=DESC --number=100
# Eliminare quelli verificati come falsi (ID di esempio)
wp user delete 4812 4813 4814 --yes
La colonna created_via dice se l’ordine è arrivato dal checkout classico (checkout) o dalla Store API (store-api), e aiuta a confermare quale porta chiudere. Prima di eliminare, conviene conservare anche un dump del database: se il fornitore dei pagamenti chiede dettagli settimane dopo, quei dati non si recuperano più.
Il card testing in sé non richiede una bonifica, ma capita spesso che arrivi insieme ad altro: chiavi del gateway esfiltrate, uno skimmer che ha alimentato gli stessi elenchi, amministratori sconosciuti in un negozio poco curato. Se gli indizi puntano anche in quella direzione, analizziamo file, database e sistema con una pulizia garantita in 6, 12 o 24 ore per ogni installazione WordPress; scrivici con le informazioni che hai raccolto dai log e dal gateway.