Ordini falsi e carding su WooCommerce: abuso del checkout e delle API REST

Centinaia di ordini falliti in una notte: come riconoscere il card testing su WooCommerce e fermarlo tra checkout, Store API, web server e gateway di pagamento.

Un modulo di checkout da cui partono file di piccoli ordini, quasi tutti segnati da una croce rossa e uno solo da una spunta, mentre un contatore di richieste al minuto sale oltre la soglia indicata da una linea gialla

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.

Schema a flusso del card testing. A sinistra un elenco di carte rubate alimenta uno script che ruota indirizzi IP attraverso proxy. Le richieste arrivano a tre endpoint del negozio: il checkout classico con wc-ajax=checkout, la Store API con /wp-json/wc/store/v1/checkout e la pagina per aggiungere un metodo di pagamento. Da lì passano al gateway e alla banca emittente, e la risposta approvata o rifiutata torna allo script, che separa le carte valide. Quattro punti numerati in giallo indicano dove si può intervenire: CDN o WAF, limiti di frequenza sul web server, rate limiting e CAPTCHA in WooCommerce, regole antifrode del gateway.
Il percorso di una carta rubata dentro il checkout, e i quattro livelli in cui si può fermare: rete, web server, WooCommerce, gateway.

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.

Tabella di confronto a due colonne tra card testing e skimmer. Righe: da dove arrivano le carte (elenchi rubati altrove, contro i clienti del negozio); gli ordini (falsi, piccoli e falliti in serie, contro ordini veri e pagati); chi segnala il problema (gateway e avvisi di tasso di rifiuto, contro clienti con addebiti sconosciuti settimane dopo); file e database (invariati salvo gli ordini, contro script iniettato nei file o nelle opzioni); primo intervento (limitare il checkout e rimborsare, contro bonifica del sito e rotazione delle chiavi). In fondo, una domanda guida: le frodi riguardano clienti reali? Se sì, cercare prima un’infezione.
Le due frodi si somigliano solo nel nome: nel carding le carte vengono da fuori, con uno skimmer vengono rubate ai tuoi clienti.

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.

Estratto di log di accesso NGINX in una finestra di terminale, con richieste POST alla Store API e al checkout classico a pochi secondi di distanza, da indirizzi IP diversi e con lo stesso user agent. Tre annotazioni a destra: nessuna visita a prodotto o carrello prima del checkout, cadenza regolare di un tentativo ogni pochi secondi, stesso user agent su indirizzi che cambiano. Sotto, l’output del conteggio per minuto mostra circa trenta tentativi al minuto contro uno o due in un’ora normale.
Nel log il card testing si riconosce più dal ritmo che dal singolo indirizzo: checkout a raffica, senza la navigazione che un cliente fa prima.

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.

IL PROSSIMO PASSO

Il tuo sito
è infetto?

Ogni ora conta: il malware continua a colpire visitatori e clienti, e Google, l’hosting e le blacklist non aspettano. Scegli il piano, paga online e condividi gli accessi: la bonifica parte subito, a prezzo fisso e con tempi garantiti.

Richiedi la bonifica

Ti porta ai piani: bonifica entro 6, 12 o 24 ore dalla ricezione degli accessi.

MANAGED SERVER S.R.L.info@rimozionemalware.com +39 02 5656 9681

Lunedì – venerdì · 09:30 – 19:30

Preferisci un modulo online?
Contattaci su managedserver.it ↗