Non è malware. Solo disattenzione — cosa la disinstallazione di un modulo non annulla

Un modulo PrestaShop a pagamento che abbiamo trovato sullo store di un cliente caricava un font decorativo da una CDN di terze parti su ogni singola pagina — la homepage, ogni categoria, ogni prodotto, il carrello, il checkout. Il font veniva usato in un solo punto: la schermata delle impostazioni del modulo stesso, in profondità nel back office, dove pressappoco una persona sola in tutta l'azienda metteva mai piede.
Ecco quanto è costata davvero quella disattenzione, misurata sulla homepage in produzione. Il modulo aggiungeva un nuovo dominio di terze parti, tre richieste in più per pagina (un foglio di stile e due file di font) e circa 159 KB di peso di cui nessun browser dei visitatori aveva bisogno. Poiché il foglio di stile stava nel <head> della pagina, era render-blocking: ogni visitatore alla prima visita attendeva una risoluzione DNS e un handshake TLS verso un server di cui il titolare dello store non aveva mai sentito parlare, prima che la pagina potesse finire di disegnarsi. Su una connessione mobile con banda limitata il Largest Contentful Paint scivolava da 2,4 a 2,9 secondi e il punteggio prestazionale di Lighthouse scendeva dai valori bassi sopra il 90 alla metà degli 80. Non catastrofico. Solo una tassa, riscossa in silenzio a ogni caricamento di pagina, per sempre, per un font che nessuno al di fuori dell'amministrazione ha mai visto.
Il raggio d'azione era l'intero store; la funzione era una sola schermata. Quel divario — tra ciò che un modulo tocca e ciò per cui in realtà serve — è l'intero argomento di questo articolo. Abbiamo limitato l'asset in modo che il font si carichi solo sulla pagina che lo utilizza, e i numeri sono tornati ai valori di riferimento. La correzione ha richiesto un pomeriggio. Scoprire che il problema c'era ha richiesto un browser e un'abitudine.

Quel modulo non era malware. È proprio questo il punto. Nessuno stava cercando di far male a nessuno. Uno sviluppatore voleva che la sua pagina delle impostazioni avesse un bell'aspetto, ha scelto un font e ha incollato lo snippet della CDN che il sito del font gli forniva — poi, per la stessa abitudine del copia-incolla, ha registrato quello stesso foglio di stile anche sull'hook globale dell'header del front office, sebbene solo la pagina delle impostazioni lo usasse davvero. Ogni decisione, presa isolatamente, era piccola e ragionevole. La somma era un peggioramento delle prestazioni esteso a tutto lo store, che nessun «ma è un modulo piccolo» avrebbe potuto prevedere. È bastata la disattenzione. Di solito basta.
Se vuole vedere quanto poco serva, ecco la forma dell'errore — ricostruita, non il codice originale del fornitore. La schermata delle impostazioni carica di per sé questo font benissimo nel back office; il danno veniva da una seconda riga, inutile, che registrava anche lo stesso foglio di stile sull'hook dell'header del front office — quello che scatta su ogni pagina dello storefront, dove nulla lo utilizza:
// Runs on EVERY page of the storefront — home, category, product, checkout
public function hookDisplayHeader($params)
{
// …yet nothing on the storefront uses this font — the settings screen loads it itself.
$this->context->controller->addCSS(
'https://3p-cdn.net/fancy-display/style.css' // third-party, render-blocking
);
}
Qui non c'è nulla di malevolo; è una manciata di righe che fanno esattamente ciò che dicono. Il problema è che questo hook non ha nulla a che vedere con la schermata delle impostazioni a cui il font è destinato. displayHeader viene renderizzato sullo storefront, quindi un font pensato per una singola pagina di amministrazione viene scaricato da ogni acquirente — per niente. La correzione consiste nell'eliminare del tutto la registrazione sullo storefront e lasciare che il back office continui a caricare il font dove viene effettivamente usato:
// The storefront never shows this font, so the front-office hook loads nothing.
public function hookDisplayHeader($params)
{
return;
}
// It loads only on this module's own settings screen in the back office —
// self-hosted, so no third-party domain and no extra DNS + TLS round-trip.
public function hookDisplayBackOfficeHeader($params)
{
if (Tools::getValue('configure') !== $this->name) {
return; // every other admin page pays nothing either
}
$this->context->controller->addCSS($this->_path.'views/css/fancy-display.css');
}
Stessa funzione, stesso font — ora lo storefront non carica nulla che non usi, e la tassa estesa a tutto lo store sparisce insieme al dominio di terze parti. Quel divario tra le due versioni è tutta la differenza tra un modulo che resta nel suo perimetro e uno che addebita silenziosamente a ogni pagina una funzione che quasi nessuno vede. Nessuno ha dovuto essere disattento di proposito.
Il problema è che i moduli fingono di essere app
La maggior parte dei commercianti ragiona sui moduli come ragiona sulle app del telefono. Un'app è isolata in una sandbox: gira nel suo giardino recintato, non può intromettersi in altre app e, se non le piace, la cancella e il telefono torna esattamente com'era. Quel modello mentale è comodo e, per PrestaShop, è completamente sbagliato.
Un modulo PrestaShop non è un'app in sandbox. È codice PHP senza sandbox che gira con tutti i privilegi del suo store. Una volta installato e abilitato, può agganciarsi a ogni pagina che viene renderizzata, leggere e scrivere qualsiasi tabella del database — ordini, clienti, prezzi, configurazione — registrare override che sostituiscono in silenzio il comportamento del core, rilasciare file nel tema, aggiungere colonne e tabelle, pianificare processi in background e chiamare servizi esterni per suo conto. Non è un ospite in un giardino recintato. È un membro del personale con le chiavi di tutto l'edificio, e Lei lo ha assunto cliccando su «installa».
Un modulo non è una funzione che si accende. È codice a cui Lei affida le chiavi del suo store. La domanda non è mai «questa funzione è carina» — è «mi fido di questo codice con tutto ciò che il mio store può fare».
Nulla di tutto questo è un difetto di PrestaShop. Proprio quella potenza è il motivo per cui la piattaforma è abbastanza estensibile da far girare un'attività seria. Ma significa che il modello di sicurezza che Lei porta in testa — il modello dell'app — non la protegge da nulla.
Detto in concreto: un singolo modulo abilitato può raggiungere tutto questo in una volta sola — si aggancia a ogni pagina che viene renderizzata, aggiunge e modifica tabelle del database, rilascia file di override sopra le classi del core, modifica il tema, carica asset su tutto il sito, pianifica processi in background, legge e scrive i suoi ordini e le anagrafiche dei clienti e chiama servizi esterni. Un'app sul telefono non può fare niente di tutto ciò al telefono. Un modulo PrestaShop può fare tutto questo al suo store — ed è per questo che «basta installarlo e vedere» è una decisione più grande di quanto sembri.

«Funzionava nel mio shop di prova» è dove iniziano i guai
Le quattro parole più costose nello sviluppo di un modulo sono «da me funzionava». Uno sviluppatore costruisce un modulo, lo installa su uno shop di prova pulito, ci clicca sopra, lo vede funzionare e lo rilascia. Il guaio è che uno shop di prova pulito non ha nulla a che fare con uno store reale.
Il suo store reale ha un tema personalizzato che sovrascrive i template che il modulo dava per scontati. Può funzionare in multishop, dove un modulo testato solo contro lo shop 1 si comporta male in silenzio sullo shop 2. Gira su una versione specifica di PHP che potrebbe essere più vecchia, o più nuova, di quella che aveva lo sviluppatore. Ha decine di altri moduli già agganciati alle stesse pagine, in competizione per lo stesso output. Ha traffico reale, uno strato di cache, un checkout in produzione che incassa denaro vero e — la cosa più importante — un giorno verrà aggiornato, a una nuova versione di PrestaShop contro cui il modulo non è mai stato testato. «Ha funzionato una volta, su uno shop, su una versione» non è garanzia di nulla. Un modulo deve continuare a funzionare in mezzo a tutto questo, per anni. È una promessa fondamentalmente più difficile di «funziona», e la maggior parte del rischio vive in quella differenza. È anche il motivo per cui la qualità dei moduli conta più della quantità, ed è la metà nascosta di ciò che rende davvero lento PrestaShop.
Cosa sopravvive quando si disabilita o si disinstalla
Ecco la convinzione che fa più danni: «se causa un problema, lo disinstallo e tutto torna alla normalità». A volte è vero. Spesso non lo è, e la differenza vale la pena di essere capita con precisione — perché è la versione sicura di sé di questa affermazione a mandare gli store in silenzioso stato di rottura.
Disabilitare un modulo impedisce che i suoi hook a runtime scattino. Questo aiuta davvero: il modulo smette di iniettare i suoi asset e di eseguire il suo codice su ogni pagina, quindi un problema di prestazioni o di visualizzazione in produzione di solito si allevia subito. Disabilitare è la prima mossa giusta in un'emergenza. Ma disabilitare non torna indietro ad annullare nulla di ciò che il modulo ha già fatto.
Disinstallare va oltre ed esegue la routine di pulizia del modulo stesso — e quella routine rimuove solo ciò che il suo autore si è preso la briga di scrivere del codice per rimuovere. Ciò che non torna in modo affidabile da solo:
- Modifiche al database e alla configurazione. Nuove tabelle, nuove colonne e righe di configurazione possono restare indietro. Alcuni moduli conservano deliberatamente i suoi dati alla disinstallazione perché non perda le impostazioni in caso di reinstallazione — una scelta ragionevole, ma solo se glielo dicono.
- Dati di ordini e clienti. Tutto ciò che viene scritto nei suoi ordini, nelle fatture o nelle anagrafiche dei clienti durante il normale funzionamento è dato aziendale in produzione, suo. Disinstallare il modulo non lo cancella, e non dovrebbe farlo — ma può lasciarlo in una forma che solo quel modulo capiva.
- Override e modifiche al tema. I file rilasciati in
/overrideo nel suo tema possono sopravvivere al modulo. Un override obsoleto lasciato al suo posto dopo la disinstallazione è una classica origine di «il mio store si è rotto e nulla di ciò che ho disabilitato ha risolto». - Integrazioni esterne. I dati che il modulo ha inviato a un servizio di terze parti — un feed, un CRM, una piattaforma di analytics o di marketing — sono già fuori dal controllo del suo store. Disinstallare non cambia nulla dall'altra parte.
Quindi la frase esatta è: disabilitare ferma l'emorragia, ma la disinstallazione non annulla le scritture su database, le modifiche di configurazione, i dati di ordini e clienti, gli override, le modifiche al tema o le chiamate esterne che un modulo ha già effettuato. «Basta che lo disinstallo» è un piano per la funzione. Non è un piano per l'impronta lasciata.
Aiuta immaginare i tre stati fianco a fianco. Disabilitare ferma l'esecuzione del modulo. Disinstallare esegue la sua routine di pulizia. Ma un'intera colonna di cose — dati scritti nei suoi ordini e clienti, configurazione, override, modifiche al tema e qualsiasi cosa già inviata a un servizio esterno — sopravvive a entrambi, a meno che l'autore del modulo non abbia scritto codice per invertirli e Lei non abbia verificato che l'abbia fatto. Quell'ultima colonna è quella che coglie di sorpresa le persone nel peggior momento possibile.

Anche noi abbiamo rilasciato questo errore
Sarebbe disonesto scrivere tutto ciò come se capitasse solo agli altri. Non è così. Costruiamo e vendiamo moduli PrestaShop per vivere, e abbiamo commesso lo stesso tipo di errore.
Su uno dei nostri moduli, uno script del front office di cui aveva bisogno una singola funzione è stato registrato su un hook che scatta su ogni pagina, anziché solo sui controller dove la funzione compare davvero. Dal punto di vista funzionale tutto funzionava, quindi ha superato la revisione ed è stato rilasciato. È stato un audit prestazionale mesi dopo — lo stesso tipo di audit di questo articolo — a cogliere un piccolo script che si caricava su tutto il sito senza motivo, su pagine che non lo usavano mai. Il costo non era drammatico: qualche kilobyte e un po' di tempo di parsing su ogni pagina, in tutto il catalogo, finché non l'abbiamo corretto. Ma era reale, era nostro, e «funziona» l'aveva fatto passare senza discutere.
Ciò che è cambiato non è stata una predica sull'essere più attenti. L'abbiamo trasformato in una domanda a cui la revisione deve rispondere per ogni asset e per ogni hook: ha davvero bisogno di essere globale, o appartiene alle pagine che lo usano? Una cicatrice diventa una regola, e la regola coglie la successiva. Questa è la versione onesta della qualità — non «non commettiamo mai errori», ma «abbiamo costruito la cosa che li coglie prima che lo faccia Lei». È la stessa disciplina dietro il portare uno store reale con oltre 80 moduli a un punteggio PageSpeed di 99: non meno moduli, ma moduli che restano nel loro perimetro — che è l'intero obiettivo progettuale della nostra suite Performance Revolution.
Allora l'IA non è il cattivo qui?
Ci si potrebbe aspettare che un fornitore di moduli concluda dando la colpa all'IA — codice a basso costo generato dall'IA che inonda il mercato di scarti. Non lo faremo, perché sarebbe sia ingiusto sia ipocrita. Usiamo noi stessi, e molto, l'ingegneria assistita dall'IA. È proprio per questo che non giudichiamo un modulo dal fatto che un'IA lo abbia toccato.
L'IA è un acceleratore. Rende più veloce la buona ingegneria e rende più veloce l'ingegneria distratta, e non ha alcuna opinione su quale delle due Lei stia facendo. L'errore del font-su-ogni-pagina precede di un decennio l'attuale ondata dell'IA; di quelli ne hanno scritti tanti esseri umani di fretta. Ciò che separa un modulo di cui ci si può fidare da uno di cui no non è mai stato lo strumento dell'autore. È la governance: c'è un proprietario con nome e cognome, il codice viene revisionato, viene testato, viene mantenuto compatibile mentre PrestaShop evolve, le sue modifiche possono essere annullate, resta dentro il suo budget prestazionale, qualcuno lo manterrà l'anno prossimo. Quelle domande sono valide esattamente allo stesso modo che il codice sia stato digitato da una persona, generato da un modello o — come ormai è normale — scritto da una persona e da un modello insieme. Proprietà, revisione e test sono il tema. La paternità è una distrazione.
Ci giudichi con lo stesso test
Vendiamo moduli anche noi, quindi sarebbe facile leggere tutto ciò come «compri da noi invece che da altri». Non ci creda sulla parola — è tutto lo spirito della cosa. La mossa corretta è tenere ogni fornitore, noi compresi, allo stesso standard, e la buona notizia è che la maggior parte dei controlli importanti non richiede alcuna alfabetizzazione in PHP. Può eseguirli da un browser su una copia di staging del suo store: installi il modulo, apra la scheda Rete del suo browser sulla homepage (non sulla pagina del modulo) e conti cosa è cambiato.
Abbiamo redatto l'intera procedura come riferimento in linguaggio semplice — come verificare un modulo PrestaShop prima di installarlo su uno store in produzione — e la intendiamo come uno strumento da usare contro il nostro catalogo con la stessa prontezza con cui lo si userebbe contro quello di chiunque altro. Se preferisce che sia qualcuno a eseguirla per Lei, è esattamente ciò che fanno i nostri audit prestazionali e audit di sicurezza, e la nostra scansione di sicurezza gratuita è un punto di partenza senza costi. Rivolga la checklist contro di noi. Preferiremmo che lo facesse.
Domande frequenti
Disinstallare un modulo cancella tutto ciò che ha creato?
No — non in modo affidabile. La disinstallazione esegue la routine di pulizia del modulo stesso, che rimuove solo ciò per cui il suo autore ha scritto del codice per rimuoverlo. Tabelle del database, righe di configurazione, file in /override, modifiche al tema e qualsiasi dato già inviato a un servizio esterno possono sopravvivere tutti. Inoltre non dovrebbe mai cancellare i suoi ordini o le anagrafiche dei clienti, perché sono i suoi dati aziendali in produzione. Dia per scontato che la disinstallazione metta in ordine la funzione, non l'intera impronta.
Un singolo modulo può davvero rallentare l'intero store?
Sì. Quando un modulo carica asset o esegue codice su un hook globale — uno che scatta su ogni pagina — quel costo viene pagato da ogni pagina, comprese la sua homepage e il checkout, anche pagine su cui la funzione non compare mai. È esattamente così che un font pensato per una singola schermata di amministrazione ha finito per tassare tutto uno storefront.
Un modulo è insicuro solo perché l'IA ha aiutato a scriverlo?
No. L'IA è un acceleratore, non un verdetto. Ciò che rende affidabile un modulo è la proprietà, la revisione, i test, la compatibilità, la reversibilità e la disciplina prestazionale — e queste valgono che il codice sia stato scritto da una persona, da un modello o da entrambi. Giudichi la governance, non la paternità.
Come faccio a controllare davvero un modulo prima di installarlo?
Su una copia di staging, lo installi e osservi cosa cambia: nuove richieste a terze parti nella scheda Rete della sua homepage, nuove tabelle del database, se il checkout funziona ancora e se si disinstalla in modo pulito. Abbiamo scritto l'intera procedura passo passo in come verificare un modulo PrestaShop prima di installarlo.
I migliori moduli sono noiosi
Dopo tutti gli aneddoti di guerra, la conclusione è quasi anticlimatica, ed è proprio questo il punto. Un buon modulo è noioso. Fa l'unica cosa che ha promesso. I suoi asset si caricano solo dove vengono usati. Tocca solo i dati di cui ha bisogno, Le dice cosa conserva e ripulisce ciò che può. Sopravvive al suo prossimo aggiornamento di PrestaShop senza drammi. E il segno più vero della sua qualità è che, sei mesi dopo averlo installato, si è completamente dimenticato che c'è.
L'eccitazione, in un modulo, è quasi sempre il rumore di qualcosa che va storto su una pagina che non avrebbe mai dovuto toccare. Noioso è l'obiettivo. Noioso è ciò che «funziona e basta» significa davvero visto dall'interno — e vale la pena verificarlo, di proposito, prima che uno sconosciuto con le chiavi di tutto il suo store venga ad abitarci.
Commenti
Ancora nessun commento. Sii il primo!
Sii il primo a fare una domanda o a condividere un feedback utile.
Lascia un commento
Condividi una domanda, un dettaglio di installazione o un feedback utile per un altro lettore.