Sicurezza di WooCommerce oltre il checkout: account clienti, chiavi API e webhook

Credential stuffing sugli account, chiavi REST API, webhook verso URL sconosciuti, gestori del negozio e gateway: cosa controllare in WooCommerce e come.

Un negozio online stilizzato con il carrello al centro e, intorno, una chiave API, un webhook con una freccia che porta gli ordini verso un server sconosciuto evidenziato in rosso e un pannello di impostazioni del gateway di pagamento con un IBAN modificato

Quando si parla di sicurezza di un negozio WooCommerce, l’attenzione va quasi tutta alla pagina di pagamento: gli skimmer che copiano i dati delle carte, i bot che provano migliaia di carte rubate. Sono rischi reali, ma non sono gli unici. Un negozio online è anche un archivio di clienti con password, un’API che accetta richieste dall’esterno, un sistema che spedisce copie degli ordini ad altri servizi e un pannello a cui accedono persone con ruoli diversi. Ognuna di queste parti può essere usata per rubare dati o per restare nel sito dopo una bonifica, e nessuna passa dal checkout.

Una chiave API con permessi di lettura o un webhook in più non fanno rumore, non modificano file e non vengono segnalati dagli scanner. Per un attaccante sono il modo più pulito di continuare a ricevere gli ordini di un negozio già ripulito.

In questo articolo guardiamo a ciò che sta intorno al checkout: gli account dei clienti, le chiavi della REST API, i webhook, il ruolo di gestore del negozio, le impostazioni dei gateway di pagamento e delle email, e le tabelle in cui WooCommerce conserva gli ordini. Per il furto dei dati delle carte nella pagina di pagamento rimandiamo all’articolo sugli skimmer JavaScript, e per gli ordini falsi usati per provare le carte a quello sul carding.

Mappa di un negozio WooCommerce con il checkout al centro, già coperto da altri articoli, e sei aree intorno evidenziate: account dei clienti nella pagina Il mio account, bersaglio del credential stuffing; chiavi della REST API nella tabella woocommerce_api_keys; webhook nella tabella wc_webhooks, che inviano ordini a URL esterni; utenti con ruolo shop_manager e capacità manage_woocommerce; impostazioni dei gateway e conti bancari in wp_options; destinatari delle email e note degli ordini. Per ciascuna area è indicato dove si trova il dato e con quale comando si controlla.
Le aree di un negozio WooCommerce che restano fuori dal checkout, con il punto del database in cui si controllano.

Account dei clienti e credential stuffing

La pagina «Il mio account» di WooCommerce è un modulo di login esposto a chiunque, e riceve lo stesso trattamento di wp-login.php: tentativi automatici con coppie di email e password rubate da altri servizi. È il credential stuffing, che OWASP definisce come l’inserimento automatizzato di credenziali rubate nei moduli di accesso per entrare negli account. Funziona perché molte persone usano la stessa password dappertutto, e un negozio con migliaia di clienti ne ha sicuramente qualcuno la cui password è già in una lista.

Un account cliente violato espone indirizzi, telefono e storico degli ordini, utili per truffe mirate via email o telefono, e con alcuni gateway anche i metodi di pagamento salvati, utilizzabili per nuovi acquisti spediti a un indirizzo diverso. Il segnale nei log è un volume di POST verso la pagina dell’account fuori scala rispetto alle visite normali:

# Tentativi di login su Il mio account e su wp-login.php per indirizzo IP
grep -hE '"POST /(my-account|mio-account)/? |"POST /wp-login\.php' /var/log/nginx/access.log* \
  | awk '{ print $1 }' | sort | uniq -c | sort -rn | head -20

# Clienti che hanno effettuato l'accesso di recente (WooCommerce registra l'ultima attività)
wp user list --role=customer --meta_key=wc_last_active --orderby=meta_value_num --order=DESC \
  --fields=ID,user_email --number=20

Le difese sono quelle di qualunque login, applicate anche alla pagina dell’account: limitazione della frequenza sul web server o sul WAF per le richieste POST a quell’indirizzo, un controllo anti-bot sul modulo, notifiche al cliente quando cambiano email o password. Per amministratori e gestori del negozio la verifica in due passaggi non è opzionale: un loro account violato vale infinitamente più di quello di un cliente.

Dopo un incidente che ha toccato la tabella degli utenti, poi, vale la pena forzare il cambio della password dei clienti o almeno invalidarne le sessioni: gli hash delle password letti dal database possono essere attaccati offline, e le sessioni attive restano valide finché non scadono. Un’email ai clienti che spiega cosa è successo e chiede di cambiare la password anche sugli altri servizi in cui l’hanno riutilizzata è parte della risposta, non un atto di cortesia.

Le chiavi della REST API

WooCommerce permette di collegare gestionali, magazzini, marketplace e app attraverso la REST API, autenticata con una coppia di chiavi. Secondo la documentazione di WooCommerce, le chiavi si generano da WooCommerce → Impostazioni → Avanzate → REST API, sono associate a un utente e hanno uno di tre livelli di permesso: lettura, scrittura, lettura e scrittura. La chiave segreta viene mostrata una sola volta, al momento della creazione.

Dal punto di vista di chi attacca, una chiave con permesso di lettura è un accesso permanente a ordini e clienti che sopravvive al cambio di tutte le password: la chiave non dipende dalla password dell’utente a cui è associata, e resta valida finché qualcuno non la revoca. Una chiave in scrittura consente anche di modificare prodotti, prezzi e ordini. Le chiavi vivono nella tabella woocommerce_api_keys: la consumer key è salvata come hash, mentre il consumer secret è conservato in chiaro, e sono leggibili la descrizione, l’utente, i permessi, le ultime sette cifre della chiave e la data dell’ultimo accesso. Chi ha potuto leggere il database, per esempio con una SQL injection, non ha quindi in mano chiavi pronte all’uso, ma chi ha avuto accesso al pannello o al database in scrittura può crearne di nuove a piacere:

# Tutte le chiavi con l'utente associato e l'ultimo utilizzo (adattare il prefisso wp_)
wp db query "SELECT k.key_id, u.user_login, k.description, k.permissions,
  k.truncated_key, k.last_access
  FROM wp_woocommerce_api_keys k LEFT JOIN wp_users u ON u.ID = k.user_id
  ORDER BY k.last_access DESC;"

# Revocare una chiave non riconosciuta (equivale al link Revoca del pannello)
wp db query "DELETE FROM wp_woocommerce_api_keys WHERE key_id = 7;"

Le domande da porsi per ogni riga sono tre. Chi l’ha creata e per quale servizio? Una descrizione generica o vuota, o un utente che non esiste più, sono campanelli d’allarme. Servono davvero i permessi di scrittura? Molte integrazioni hanno bisogno solo di leggere. Quando è stata usata l’ultima volta? Una chiave mai usata da un anno si può revocare; una chiave usata stanotte da un servizio che nessuno riconosce va revocata subito, e l’indirizzo IP da cui arrivano le sue richieste va cercato nei log di accesso, filtrando le richieste verso /wp-json/wc/.

Quando le integrazioni sono poche e hanno indirizzi IP fissi, come spesso accade con un gestionale o un servizio di spedizioni, si può anche limitare l’accesso agli endpoint /wp-json/wc/ a quegli indirizzi direttamente sul web server. Non sostituisce la revisione delle chiavi, ma rende inutilizzabile una chiave rubata da chi si collega da un’altra rete. Va fatto con attenzione: il filtro va applicato solo alle versioni usate dalle integrazioni, come /wp-json/wc/v3/, e mai a /wp-json/wc/store/, che serve al carrello e al checkout a blocchi di tutti i clienti; anche il pannello e alcuni plugin richiamano questi endpoint dal browser di chi amministra, quindi il filtro va provato su un ambiente di test prima di arrivare in produzione.

Webhook: una copia di ogni ordine a un indirizzo sconosciuto

I webhook sono il meccanismo con cui WooCommerce avvisa un servizio esterno quando succede qualcosa: un ordine creato, un cliente registrato, un prodotto modificato. Si configurano in WooCommerce → Impostazioni → Avanzate → Webhook e, come descrive la documentazione dei webhook, ciascuno ha uno stato, un argomento, un URL di consegna e un segreto usato per firmare i messaggi. A ogni evento, WooCommerce invia all’URL il contenuto completo dell’oggetto: per un ordine, nomi, indirizzi, email, telefono, prodotti e importi.

Un webhook su «Ordine creato» che punta a un dominio dell’attaccante è quindi un sistema di esfiltrazione perfetto. Non richiede file sul server, non inietta codice nella pagina e non viene visto dagli scanner. Sopravvive alla bonifica dei file, alla reinstallazione di WordPress e al cambio delle password, perché è un dato nel database. E usa una funzione legittima, con traffico in uscita identico a quello di un’integrazione vera. È il motivo per cui un negozio può continuare a perdere dati dei clienti anche dopo una bonifica dei file fatta bene, senza che sul disco resti un solo file malevolo.

Flusso di un ordine WooCommerce. Il cliente completa il checkout; WooCommerce salva l’ordine nella tabella wc_orders e genera l’evento order.created; la tabella wc_webhooks contiene due webhook attivi sullo stesso argomento. Il primo consegna a gestionale.esempio.it, un’integrazione riconosciuta, con descrizione e utente noti. Il secondo consegna a un dominio registrato di recente, con nome generico e creato da un utente shop_manager aggiunto il giorno dell’intrusione. Un’annotazione rossa spiega che il secondo webhook sopravvive alla pulizia dei file, alla reinstallazione del core e al cambio delle password, perché è un record del database.
Un webhook malevolo usa lo stesso meccanismo delle integrazioni legittime: a distinguerlo sono il dominio di destinazione, chi l’ha creato e quando.
# Webhook con destinazione, argomento, autore e data di creazione
wp db query "SELECT webhook_id, status, name, user_id, topic, delivery_url,
  date_created, failure_count FROM wp_wc_webhooks ORDER BY date_created DESC;"

# In alternativa con WP-CLI (i comandi wc richiedono --user con un amministratore)
wp wc webhook list --user=1 --fields=id,name,status,topic,delivery_url

# Disattivare subito, eliminare dopo aver conservato i dati per l'analisi
wp wc webhook update 12 --status=disabled --user=1
wp wc webhook delete 12 --force=true --user=1

Per ogni webhook si verifica che il dominio di destinazione appartenga a un servizio che il negozio usa davvero, e che la data di creazione non coincida con il periodo della compromissione. WooCommerce conserva anche i log delle consegne, consultabili dal menu Stato → Log, utili per capire da quando i dati partono e quanti ordini sono stati inviati: un’informazione indispensabile per valutare la violazione, come spieghiamo nell’articolo su GDPR e data breach.

Il ruolo di gestore del negozio

WooCommerce aggiunge il ruolo shop_manager, pensato per chi gestisce ordini e prodotti senza essere amministratore. È un ruolo potente: ha la capacità manage_woocommerce, che nel codice di WooCommerce controlla l’accesso alle impostazioni del negozio, e quindi anche alla creazione di chiavi API, ai webhook e alla configurazione dei gateway di pagamento. Ha inoltre capacità di WordPress come edit_theme_options, import ed export, e può modificare gli utenti con ruolo cliente.

Per un attaccante, creare un gestore del negozio è spesso più furbo che creare un amministratore: molti controlli dopo un incidente cercano solo gli amministratori fantasma, e un utente shop_manager con un nome plausibile passa inosservato. Per la stessa ragione, un gestore reale con una password debole è un bersaglio di valore.

La regola del privilegio minimo vale anche qui. Chi evade gli ordini o aggiorna il catalogo non ha bisogno di toccare le impostazioni dei pagamenti: per queste persone conviene un ruolo più ristretto, creato con un plugin di gestione dei ruoli o con poche righe di codice, lasciando manage_woocommerce a chi configura davvero il negozio. Gli account di collaboratori, agenzie e stagisti vanno rimossi quando il rapporto finisce, non quando ci si ricorda di farlo.

# Gestori del negozio e amministratori, con data di registrazione
wp user list --role__in=administrator,shop_manager \
  --fields=ID,user_login,user_email,roles,user_registered

Gateway di pagamento, conti bancari ed email

Con l’accesso alle impostazioni, l’attacco più diretto è cambiare dove vanno i soldi. Le impostazioni di ogni gateway sono salvate in wp_options con nomi del tipo woocommerce_ID_settings: chiavi del fornitore di pagamento, account di destinazione, URL di ritorno. Il bonifico bancario offline salva i conti in un’opzione separata, woocommerce_bacs_accounts: un IBAN sostituito in quell’opzione compare nelle email di conferma di ogni ordine pagato con bonifico, e i clienti pagano l’attaccante senza che nulla sembri fuori posto.

Meno appariscente, ma altrettanto utile per chi ruba dati, è la configurazione delle email. L’email «Nuovo ordine» per l’amministratore ha un campo destinatario salvato in woocommerce_new_order_settings: un indirizzo aggiunto lì riceve una copia di ogni ordine. Anche le note degli ordini, salvate come commenti di tipo order_note, vanno controllate: una nota inviata al cliente con un link di pagamento alternativo è una truffa che parte dal dominio del negozio.

# Conti del bonifico bancario e destinatari dell'email Nuovo ordine
wp option get woocommerce_bacs_accounts --format=json
wp option pluck woocommerce_new_order_settings recipient

# Impostazioni dei gateway: confrontare chiavi e account con quelli del fornitore
wp db query "SELECT option_name FROM wp_options WHERE option_name LIKE 'woocommerce\_%\_settings';"

# Note degli ordini che contengono link
wp db query "SELECT comment_post_ID, comment_date, LEFT(comment_content, 120)
  FROM wp_comments WHERE comment_type = 'order_note' AND comment_content LIKE '%http%'
  ORDER BY comment_date DESC LIMIT 30;"

Le chiavi dei gateway vanno confrontate con quelle visibili nel pannello del fornitore di pagamento, non solo lette: una chiave pubblica sostituita con quella di un altro account ha lo stesso formato di quella giusta. Nel dubbio, si rigenerano dal pannello del fornitore e si aggiornano nel negozio.

Ordini e tabelle HPOS: dove guardare

Dalla versione 8.2, secondo la documentazione per sviluppatori, i nuovi negozi usano l’archiviazione ad alte prestazioni degli ordini (HPOS), con tabelle dedicate: wc_orders, wc_order_addresses, wc_order_operational_data e wc_orders_meta. I negozi più vecchi possono ancora usare le tabelle dei post, o entrambe in modalità di compatibilità. Sapere quale archivio è quello autorevole evita di cercare nel posto sbagliato:

# yes = gli ordini autorevoli sono nelle tabelle HPOS
wp option get woocommerce_custom_orders_table_enabled

# Da dove arrivano gli ordini: checkout, admin, rest-api...
wp db query "SELECT created_via, COUNT(*) FROM wp_wc_order_operational_data GROUP BY created_via;"

Un picco di ordini creati via rest-api che non corrisponde a un’integrazione nota, o ordini modificati da un utente che non dovrebbe gestirli, sono tracce da incrociare con le chiavi API e con i log. Anche i metadati degli ordini meritano un’occhiata: alcuni skimmer salvano i dati raccolti proprio lì, in campi con nomi plausibili. In modalità di compatibilità, infine, gli stessi dati esistono in due copie: le correzioni fatte a mano via SQL non passano dalla sincronizzazione di WooCommerce, quindi vanno fatte con gli strumenti di WooCommerce o su entrambe le copie, altrimenti le due versioni divergono.

Un controllo periodico, prima e dopo la bonifica

Tutti i controlli visti sono letture veloci, e messi insieme formano un audit che richiede pochi minuti. Conviene farlo in tre momenti: subito dopo una compromissione, prima di dichiarare chiusa la bonifica e poi a cadenza regolare, per esempio ogni mese insieme agli aggiornamenti. Tenere un elenco scritto delle integrazioni legittime, con chiave, webhook e referente di ciascuna, trasforma l’audit in un confronto: ciò che non è nell’elenco va spiegato o rimosso.

Tabella di audit in sei righe. Per ogni elemento sono indicati dove si trova, cosa cercare e l’azione. Chiavi API: tabella woocommerce_api_keys, descrizione vuota, permessi di scrittura non necessari, ultimo accesso inatteso; revocare. Webhook: tabella wc_webhooks, domini sconosciuti, data di creazione nel periodo dell’incidente; disattivare e poi eliminare. Utenti: ruoli administrator e shop_manager, account registrati di recente; rimuovere e cambiare password. Gateway: opzioni woocommerce_ID_settings, chiavi diverse da quelle del fornitore; rigenerare. Bonifico ed email: woocommerce_bacs_accounts e destinatari di Nuovo ordine; ripristinare. Ordini: created_via e note con link; incrociare con i log.
L’audit di un negozio WooCommerce oltre il checkout: sei elementi, dove si trovano e cosa fare quando qualcosa non torna.

Questi elementi vanno letti insieme alla bonifica dei file e del sistema, non al posto di essa: una chiave API rubata dice come l’attaccante legge i dati, non come è entrato. Per il resto della messa in sicurezza, la checklist di hardening dopo la bonifica e i log di audit aiutano a tenere traccia di chi modifica impostazioni e utenti. Se gestisci un negozio compromesso o sospetti che i dati dei clienti stiano uscendo, contattaci: controlliamo file, sistema e database, comprese chiavi, webhook e gateway, con una pulizia garantita in 6, 12 o 24 ore per installazione dal ricevimento degli accessi.

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 ↗