# Verificare la presenza di codice iniettato nel database

> Verificare codice dannoso nel database: come trovare script iniettati, indirizzi estranei, trigger e account con query in sola lettura, senza distruggere dati.

Fonte: https://phpsos.de/it/blog/datenbank-auf-schadcode-pruefen/  
Stato: 25/10/2026  
Fornitore: PHP SOS, Assistenza di emergenza PHP e sicurezza dei server. Assistenza immediata su WhatsApp: https://wa.me/491736494914?text=Buongiorno%20PHP%20SOS%2C%20abbiamo%20bisogno%20di%20aiuto%20con%20il%20nostro%20server%20PHP.%20Azienda%3A%20%E2%80%A6%20Sito%20web%3A%20%E2%80%A6

**In breve:** per verificare la presenza di codice dannoso nel database, scandisca un'esportazione o una copia con query in sola lettura alla ricerca di script iniettati, indirizzi estranei e codice offuscato in contenuti e impostazioni. Controlli inoltre trigger, eventi pianificati, stored procedure e utenti del database. Bonifichi solo dopo la valutazione e mai con un cieco cerca e sostituisci, perché altrimenti i dati serializzati si rompono.

## Il punto cieco di molte bonifiche

Dopo un'intrusione la maggior parte dei gestori controlla i file. Sostituiscono il core del CMS, cancellano i file PHP sospetti e reinstallano le estensioni. Il sito poi sembra pulito e una settimana dopo reindirizza di nuovo verso pagine estranee. La ragione sta spesso nel database, che è stato ripreso invariato durante la bonifica.

Per gli aggressori il database è un nascondiglio attraente. Uno script in un widget viene consegnato su ogni pagina. Un'impostazione di indirizzo modificata devia tutti i visitatori. Un account amministratore in più apre la porta per il futuro. Nulla di tutto ciò emerge in una scansione dei file.

Dopo PHP2Shell, le vulnerabilità CVE-2026-109618 e CVE-2026-109619 con esecuzione di codice senza autenticazione, il database rientra perciò in ogni verifica. Chi può eseguire codice sul server può di norma leggere dalla configurazione le credenziali del database e scrivervi a piacere. Come l'applicazione dialoga con il database lo spiega [PHP e database: PDO e mysqli](https://phpsos.de/it/php/php-und-datenbanken/).

## Dove si nasconde il codice dannoso nel database

| Luogo | Contenuto tipico | Effetto |
|---|---|---|
| Contenuti (articoli, pagine, prodotti) | blocchi `<script>`, link invisibili, `<iframe>` | codice dannoso o spam per i visitatori |
| Impostazioni e opzioni | indirizzo del sito modificato, script estranei in widget od opzioni del tema | reindirizzamenti, script su tutte le pagine |
| Tabelle degli utenti | amministratori aggiuntivi | accesso permanente |
| Trigger | codice che a ogni salvataggio modifica i contenuti | il codice dannoso ritorna dopo la bonifica |
| Eventi pianificati | attività ricorrenti nel server del database | modifiche senza accesso web |
| Utenti del database | account aggiuntivi con ampi privilegi | accesso che aggira il CMS |

Le ultime tre righe vengono trascurate particolarmente spesso, perché non si trovano nelle tabelle del CMS ma nel server del database stesso.

Per gli shop online un punto merita particolare attenzione: le impostazioni attraverso cui vengono inclusi script aggiuntivi nel checkout e nella conclusione dell'ordine. Uno script estraneo in quel punto può leggere i dati inseriti dai clienti prima che vengano trasmessi cifrati al servizio di pagamento. Verifichi quindi in modo mirato tutti i campi per il codice di intestazione e piè di pagina, le integrazioni di tracciamento e le impostazioni del design che agiscono sulle pagine di cassa.

Pensi inoltre ad altri database sullo stesso server. Copie di test e staging, vecchie versioni di progetto o database di altri siti si trovano spesso accanto e sono raggiungibili con le stesse credenziali. Ciò che viene trovato nel database live andrebbe verificato anche lì, prima che una copia serva di nuovo come base.

## Verificare codice dannoso nel database: contenuti e impostazioni

Lavori su un'esportazione. È al contempo conservazione delle prove e base di ricerca. L'esportazione si può scandire come file di testo senza gravare sul database in funzione:

```bash
# Creare un'esportazione consistente (le credenziali vengono richieste)
mysqldump --single-transaction --routines --triggers --events -u BENUTZER -p DATENBANK > export.sql
sha256sum export.sql > export.sql.sha256

# Contare i modelli tipici nell'esportazione
grep -oiE '<script[^>]{0,80}' export.sql | sort | uniq -c | sort -rn | head -30
grep -oiE '(eval\(|base64_decode|fromCharCode|document\.write|atob\()' export.sql | sort | uniq -c
grep -oiE 'https?://[a-z0-9.-]+' export.sql | sort | uniq -c | sort -rn | head -50
```

L'ultima query elenca per frequenza tutti i domini presenti nel database. I domini estranei che nessuno nel team conosce sono i candidati più importanti. Per query mirate nel database stesso sono adatti i comandi SELECT. L'esempio usa tabelle di WordPress; prefisso e nomi delle tabelle di altri sistemi sono nella loro documentazione:

```sql
-- Impostazioni con script o funzioni sospette
SELECT option_name, LENGTH(option_value) AS laenge
FROM wp_options
WHERE option_value LIKE '%<script%'
   OR option_value LIKE '%eval(%'
   OR option_value LIKE '%base64_decode%'
ORDER BY laenge DESC;
```

Le voci con un contenuto molto grande meritano particolare attenzione. Approfondimenti sui nascondigli specifici di WordPress sono nella guida [Trovare backdoor in WordPress](https://phpsos.de/it/ratgeber/backdoor-wordpress-finden/).

## Trigger, eventi e account del database

Trigger ed eventi pianificati in molte applicazioni web non sono nemmeno previsti. Se esistono, qualcuno dovrebbe saper spiegare perché. Queste query leggono soltanto dalle tabelle di sistema di MySQL e MariaDB:

```sql
-- Trigger in tutti i database
SELECT TRIGGER_SCHEMA, TRIGGER_NAME, EVENT_OBJECT_TABLE, CREATED
FROM information_schema.TRIGGERS;

-- Eventi pianificati
SELECT EVENT_SCHEMA, EVENT_NAME, STATUS, CREATED, LAST_EXECUTED
FROM information_schema.EVENTS;

-- Stored procedure e funzioni
SELECT ROUTINE_SCHEMA, ROUTINE_NAME, ROUTINE_TYPE, CREATED
FROM information_schema.ROUTINES
WHERE ROUTINE_SCHEMA NOT IN ('mysql', 'sys', 'information_schema', 'performance_schema');

-- Utenti del database
SELECT user, host FROM mysql.user ORDER BY user;
```

Se la Sua applicazione usa PostgreSQL o un altro sistema di database, tabelle di sistema e comandi hanno nomi diversi; il principio resta lo stesso. Per l'analisi si raccomanda un utente del database dedicato, con soli permessi di lettura. Così nemmeno un errore di battitura in una query può modificare qualcosa e la verifica non lascia tracce nei dati.

Un trigger che a ogni salvataggio di un articolo aggiunge codice spiega perché il codice dannoso ritorna dopo ogni bonifica. Gli utenti del database sconosciuti rientrano nella verifica degli account tanto quanto gli account amministratore nel CMS; maggiori informazioni in [Trovare account amministratore estranei in CMS e server](https://phpsos.de/it/blog/fremde-admin-konten-finden/).

## Bonificare in modo pulito, senza distruggere dati

La bonifica è la parte più delicata. Quest'ordine si è dimostrato valido:

1. **Valutare i reperti:** ogni riscontro viene classificato come noto, spiegabile come innocuo o estraneo. I codici di tracciamento e delle mappe sono spesso legittimi.
2. **Chiudere il punto d'ingresso:** portare PHP a una versione corretta (8.5.12, 8.4.27, 8.3.36, 8.2.35 o backport confermato), riavviare tutti i worker, aggiornare l'applicazione.
3. **Rimuovere in modo mirato:** bonificare i contenuti estranei tramite l'applicazione o con strumenti che trattano correttamente i dati serializzati. Eliminare trigger, eventi e account estranei.
4. **Cambiare le credenziali:** nuova password del database, da inserire nella configurazione dell'applicazione, e permessi dell'utente dell'applicazione limitati al proprio database.
5. **Ricontrollare:** ripetere le query di ricerca dopo alcuni giorni.

> **Importante:**
> Non sostituisca nulla con cerca e sostituisci nell'esportazione SQL. I dati PHP serializzati memorizzano la lunghezza di ogni stringa. Se la lunghezza cambia, l'impostazione diventa illeggibile e il sito può andare fuori servizio.

I reindirizzamenti che compaiono nonostante un database pulito hanno la loro causa in un altro strato. L'articolo [Il sito reindirizza verso pagine estranee](https://phpsos.de/it/blog/website-leitet-um/) aiuta a circoscriverla.

## Come aiuta PHP SOS in concreto?

- Mettiamo al sicuro il database con checksum e scandiamo l'esportazione alla ricerca di script, domini estranei e codice offuscato.
- Verifichiamo trigger, eventi, procedure e utenti del database che si trovano fuori dal CMS.
- Bonifichiamo i reperti nell'ambito della [rimozione del malware](https://phpsos.de/it/leistungen/malware-entfernung/), senza danneggiare i dati serializzati.
- Limitiamo i permessi dell'utente dell'applicazione e ripetiamo la verifica dopo la bonifica.


## Domande frequenti

**Il codice dannoso può nascondersi nel database?**  
Sì. Gli aggressori scrivono JavaScript in articoli, descrizioni di prodotto o widget, modificano le impostazioni di indirizzo per i reindirizzamenti o creano account amministratore. In MySQL e MariaDB anche trigger ed eventi pianificati possono modificare i dati. Una scansione dei file non ne trova nulla.

**Come cerco nel database senza rompere nulla?**  
Lavori su un'esportazione o su una copia e usi solo query SELECT. Un'esportazione si può inoltre scandire come file di testo con grep. Le modifiche avvengono solo dopo aver valutato ogni reperto e disponendo di un backup.

**Perché non devo bonificare i reperti con cerca e sostituisci nell'esportazione?**  
Molti CMS memorizzano le impostazioni come dati PHP serializzati, in cui viene salvata anche la lunghezza di ogni stringa. Una sostituzione cambia la lunghezza ma non l'indicazione, e l'impostazione diventa illeggibile. Bonifichi tramite l'applicazione o con strumenti che comprendono i dati serializzati.

**Ogni script nel database è sospetto?**  
No. Anche codici di tracciamento, mappe, video o widget di chat vengono memorizzati come script. Decisivo è se qualcuno nel team conosce la voce e l'indirizzo di destinazione.

## Fonti

- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [OWASP Cheat Sheet](https://cheatsheetseries.owasp.org/)
- [php.net: avvisi di sicurezza](https://www.php.net/)
