Situazione attuale: PHP2Shell. Due vulnerabilità critiche di PHP (CVSS 9,2) consentono codice dannoso senza autenticazione. Patch dal 21/10/2026.Che cosa fare ora →

PHP e database: PDO e mysqli

PHP dialoga con i database tramite PDO o mysqli. Qui vede le differenze, le query sicure con prepared statement e che cosa fare con gli accessi al database dopo un incidente sul server.

Stato 6 min di letturaConoscere PHP

In breve: PHP accede ai database tramite due interfacce diffuse: PDO (PHP Data Objects) lavora con molti sistemi di database attraverso un'interfaccia uniforme, mysqli è tagliata su MySQL e MariaDB. Con entrambe i prepared statement, cioè query con segnaposto, proteggono in modo affidabile dalla SQL injection. Da PHP 8.0 (PDO) ovvero 8.1 (mysqli) entrambe segnalano per impostazione predefinita gli errori come eccezione.

Come PHP dialoga con i database

Quasi ogni applicazione PHP memorizza i propri contenuti in un database: pagine, ordini, account utente, impostazioni. Lo script PHP stabilisce per questo una connessione, invia una query nel linguaggio SQL ed elabora il risultato. Le credenziali di accesso stanno di solito in un file di configurazione sullo stesso server.

Per la direzione è importante, perché il database contiene di norma i dati più preziosi dell'azienda. Chi può eseguire codice sul server web può di solito anche leggere il file di configurazione e accedere al database con quelle credenziali.

PDO e mysqli a confronto

Caratteristica PDO mysqli
Database molti, tramite driver come PDO_MYSQL, PDO_PGSQL, PDO_SQLITE, PDO_SQLSRV, PDO_OCI MySQL e MariaDB
Segnaposto nominati (:name) e posizionali (?) posizionali (?)
Stile orientato agli oggetti orientato agli oggetti e procedurale
Errori come eccezione predefinito da PHP 8.0.0 predefinito da PHP 8.1.0
Forma breve per query con parametri prepare() ed execute() con array execute_query() da PHP 8.2.0

Nella pratica spesso decide il framework o il CMS. Molti portano un proprio livello di database che internamente usa PDO o mysqli. Chi rileva un'applicazione può stabilire con una semplice ricerca nel codice sorgente quale interfaccia venga usata e dove nascano le query:

# Dove l'applicazione stabilisce le connessioni, dove nascono le query?
grep -rn --include='*.php' -E 'new PDO|new mysqli|mysqli_connect|->query\(' /var/www/app/src | head -50

I risultati con ->query( non sono automaticamente insicuri. Meritano però una seconda occhiata, perché lì i valori possono finire direttamente nel testo SQL invece di essere passati tramite segnaposto. Proprio i progetti più vecchi mescolano i due stili, e il controllo vale la pena prima di ogni aggiornamento importante.

Prepared statement: il modello più importante

Con un prepared statement la query viene inviata al database con segnaposto e i valori vengono passati separatamente. Secondo il manuale PHP questo protegge dalla SQL injection se tutti gli input dell'utente passano attraverso segnaposto.

<?php
declare(strict_types=1);

$pdo = new PDO(
    'mysql:host=localhost;dbname=shop;charset=utf8mb4',
    $dbUser,
    $dbPass,
    [PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC]
);

$stmt = $pdo->prepare('SELECT id, name FROM kunden WHERE plz = :plz AND aktiv = :aktiv');
$stmt->execute(['plz' => $plz, 'aktiv' => 1]);

foreach ($stmt as $zeile) {
    echo htmlspecialchars($zeile['name'], ENT_QUOTES, 'UTF-8'), "\n";
}

Lo stesso con mysqli nella forma breve disponibile da PHP 8.2:

<?php
$db = new mysqli('localhost', $dbUser, $dbPass, 'shop');
$ergebnis = $db->execute_query('SELECT id, name FROM kunden WHERE plz = ?', [$plz]);

foreach ($ergebnis as $zeile) {
    echo htmlspecialchars($zeile['name'], ENT_QUOTES, 'UTF-8'), "\n";
}

Gli sviluppatori dovrebbero conoscere due limiti. I segnaposto non devono stare tra virgolette; nelle ricerche con LIKE i caratteri jolly % vanno nel valore passato. E i segnaposto sostituiscono solo valori, non nomi di tabelle o colonne. Come risolvere in sicurezza questi casi particolari lo mostra la guida Prevenire la SQL injection in PHP.

Gestione degli errori: eccezioni invece di errori silenziosi

In passato entrambe le interfacce lavoravano per impostazione predefinita in modo silenzioso: una query fallita restituiva false e chi non lo controllava continuava a lavorare con dati vuoti. Ciò è cambiato:

  • PDO: da PHP 8.0.0 PDO::ERRMODE_EXCEPTION è il valore predefinito. Gli errori lanciano una PDOException.
  • mysqli: da PHP 8.1.0 la segnalazione è impostata su MYSQLI_REPORT_ERROR e MYSQLI_REPORT_STRICT. Gli errori lanciano una mysqli_sql_exception; in precedenza la segnalazione era disattivata.

Per la sicurezza significa: le eccezioni vanno intercettate e registrate, ma non devono mai finire nel browser con testo SQL, nomi di tabelle o credenziali. Come separare le cose in modo pulito lo descrive la pagina Errori ed eccezioni in PHP.

Assegnare correttamente credenziali e permessi

Il database è protetto solo quanto le sue credenziali. Si sono dimostrate valide queste regole:

  1. Un utente proprio per ogni applicazione: non usare mai l'amministratore del database per il sito web.
  2. Solo i permessi necessari: un sito web di solito ha bisogno di leggere, scrivere, modificare e cancellare nel proprio database, ma non di permessi su altri database o funzioni del server.
  3. Nessuna connessione remota senza motivo: il database dovrebbe essere raggiungibile solo dal server web, non da internet.
  4. Credenziali fuori dal webroot: i file di configurazione e .env non devono essere consultabili via URL. Maggiori dettagli nell'articolo Proteggere credenziali e file .env.
  5. Connessione cifrata con server separati: se il database si trova su un altro computer, la connessione dovrebbe essere cifrata, perché credenziali e contenuti non viaggino in chiaro sulla rete.
  6. Accessi propri per la manutenzione: backup, analisi e amministratori ricevono utenti propri. Così nel log si può ricostruire chi ha fatto che cosa e un accesso può essere bloccato senza disturbare il sito web.

Database, PHP2Shell e il caso grave

PHP2Shell non riguarda il database in sé, ma l'interprete PHP: CVE-2026-109618 e CVE-2026-109619 consentono di eseguire codice dannoso senza autenticazione. Se ci riesce, il codice gira con i permessi del processo PHP e può quindi di norma leggere il file di configurazione con le credenziali del database. I prepared statement non aiutano, perché l'attacco non passa affatto da una query SQL.

È quindi obbligatorio l'aggiornamento a PHP 8.5.12, 8.4.27, 8.3.36 o 8.2.35 e il riavvio di tutti i processi PHP. Se ci sono indizi di un attacco riuscito, rientrano nuove credenziali del database, una verifica del database alla ricerca di contenuti iniettati e una valutazione dell'obbligo di notifica ai sensi del GDPR. Qui è sensata una incident response strutturata.

Consiglio

Cambi le password del database solo dopo la bonifica del server. Finché gira codice dannoso, questo può leggere di nuovo anche le nuove credenziali.

Come aiuta concretamente PHP SOS?

  • Verifichiamo come la Sua applicazione accede al database e se utenti, permessi e accesso di rete corrispondono al minimo indispensabile.
  • Controlliamo se i file di configurazione e di accesso stanno fuori dal webroot e non sono raggiungibili pubblicamente.
  • Dopo un incidente rinnoviamo le credenziali nell'ordine corretto e verifichiamo che nel database non ci sia codice iniettato.
  • Documentiamo i risultati in modo che responsabili della protezione dei dati e assicuratori possano seguirli.

Domande frequenti

Devo usare PDO o mysqli?

Per i nuovi progetti PDO è di solito la scelta più flessibile, perché lavora con molti database attraverso la stessa interfaccia. mysqli ha senso se usa esclusivamente MySQL o MariaDB e le servono le loro funzioni specifiche. Entrambi sono sicuri se i prepared statement vengono usati in modo coerente.

PDO lancia automaticamente eccezioni in caso di errore?

Sì, da PHP 8.0.0 PDO::ERRMODE_EXCEPTION è il valore predefinito. In precedenza c'era la modalità silenziosa, in cui gli errori erano consultabili solo tramite errorCode() ed errorInfo(). Le applicazioni più vecchie spesso impostano ancora espressamente la modalità.

I segnaposto possono sostituire anche nomi di tabelle o colonne?

No. I segnaposto valgono solo per i valori. I nomi di tabelle e colonne, ad esempio per un ordinamento, devono essere verificati rispetto a un elenco fisso di nomi consentiti prima di essere inseriti nella query.

Dopo PHP2Shell devo cambiare la password del database?

Il solo aggiornamento non lo richiede. Se però ci sono indizi che il server fosse compromesso, tutte le credenziali presenti nei file di configurazione vanno considerate note. In tal caso andrebbero rinnovate dopo la bonifica.

Fonti

Contatto immediato

Ogni ora conta. Ci scriva adesso.

Descriva brevemente sistema, versione di PHP e quanto osservato. Ci faremo sentire, chiariremo la situazione e lavoreremo da remoto fino alla chiusura e alla documentazione dell'incidente.

Aiuto immediato