In breve: per i compiti di sicurezza più frequenti PHP offre funzioni già pronte e collaudate: password_hash() per le password, random_bytes() e random_int() per i token, htmlspecialchars() contro il cross-site scripting, query preparate con PDO contro la SQL injection, hash_equals() per confronti sicuri e l'estensione Sodium per la crittografia. Chi usa questi elementi in modo coerente evita la maggior parte delle vulnerabilità applicative. Contro gli errori nell'interprete PHP stesso, come in PHP2Shell, non servono; lì aiuta solo l'aggiornamento.
Perché funzioni di sicurezza integrate in PHP?
Scrivere da sé il codice di sicurezza è soggetto a errori. Un hash di password fatto in casa, un generatore di token costruito in proprio o un filtro improvvisato per gli output HTML sembrano spesso corretti e non lo sono. Le funzioni integrate sono documentate, testate e mantenute con gli aggiornamenti di PHP.
Per chi decide significa: non chieda alla Sua agenzia o al Suo team di sviluppo se le funzioni di sicurezza siano state costruite in proprio, ma se vengano usate le funzioni standard del linguaggio. La tabella offre una panoramica.
| Compito | Funzione | Disponibile da | Avvertenza importante |
|---|---|---|---|
| Memorizzare le password | password_hash(), password_verify() |
PHP 5.5 | colonna fino a 255 caratteri; bcrypt tronca a 72 byte |
| Token casuali | random_bytes(), random_int() |
PHP 7.0 | mai rand() o mt_rand() per i segreti |
| Casualità orientata agli oggetti | Random\Randomizer |
PHP 8.2 | stessa sicurezza, interfaccia più flessibile |
| Neutralizzare l'output HTML | htmlspecialchars() |
da sempre | i flag predefiniti da 8.1 neutralizzano anche gli apici singoli |
| Confronto a tempo costante | hash_equals() |
PHP 5.6 | input dell'utente come secondo argomento |
| Crittografia moderna | Sodium (sodium_*) |
PHP 7.2 | invece di una crittografia propria |
| Segreti negli stack trace | #[\SensitiveParameter] |
PHP 8.2 | il valore non compare nel trace |
| Verificare gli input | filter_var() |
PHP 5.2 | verifica il formato, non sostituisce la neutralizzazione |
Password e token
password_hash() genera un hash con salt, password_verify() lo verifica. Con PASSWORD_DEFAULT PHP usa attualmente bcrypt; da PHP 8.4 il fattore di costo predefinito, secondo il manuale, è 12 invece di 10. Poiché l'algoritmo predefinito può cambiare, il manuale raccomanda una colonna di database da 255 caratteri. Con bcrypt le password vengono troncate dopo 72 byte, cosa da considerare per passphrase molto lunghe.
<?php
// Registrazione
$hash = password_hash($passwort, PASSWORD_DEFAULT);
// Accesso, incluso l'aggiornamento automatico dei vecchi hash
if (password_verify($eingabe, $hash)) {
if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
$hash = password_hash($eingabe, PASSWORD_DEFAULT); // salvare di nuovo
}
}
// Token per un link di reimpostazione della password
$token = bin2hex(random_bytes(32));
Per confrontare dei segreti, ad esempio una firma, va usata hash_equals(). Un normale confronto con === può rivelare, secondo il manuale, attraverso il tempo di esecuzione da quale posizione due valori differiscano. Più in dettaglio: Memorizzare in modo sicuro le password in PHP e numeri casuali e token sicuri.
Neutralizzare gli output e interrogare il database in sicurezza
Il cross-site scripting nasce quando input dell'utente finiscono senza filtro nell'HTML. htmlspecialchars() converte i caratteri speciali in entità HTML. Da PHP 8.1 i flag predefiniti sono ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401; prima gli apici singoli non venivano convertiti. Chi deve supportare versioni più vecchie indica i flag in modo esplicito.
La SQL injection si previene con query preparate. I valori vengono trasmessi separatamente dal testo SQL e non possono modificare la query:
<?php
$stmt = $pdo->prepare('SELECT id, name FROM kunden WHERE email = :email');
$stmt->execute(['email' => $email]);
$kunde = $stmt->fetch();
echo htmlspecialchars($kunde['name'] ?? '', ENT_QUOTES, 'UTF-8');
I dettagli sono in Prevenire il cross-site scripting in PHP e nella pagina sulla SQL injection.
Verificare gli input è un secondo passaggio, distinto. filter_var() accerta se un valore ha un formato valido, ad esempio un indirizzo e-mail o un intero in un intervallo ammesso. Questo però non sostituisce la neutralizzazione in output né una query preparata, perché anche valori formalmente validi possono contenere caratteri speciali.
Tenere i segreti fuori dai messaggi di errore
Una fuga di dati sottovalutata sono gli stack trace. Quando in una funzione si verifica un errore, PHP registra la catena di chiamate con gli argomenti. Se vi compare una password o una chiave API, finisce nel log. Da PHP 8.2 l'attributo #[\SensitiveParameter] contrassegna tali parametri; il loro valore compare allora nel trace solo come oggetto SensitiveParameterValue.
<?php
function anmelden(string $benutzer, #[\SensitiveParameter] string $passwort): bool
{
// ... verifica ...
throw new RuntimeException('Datenbank nicht erreichbar');
}
Secondo un'avvertenza del manuale, l'attributo agisce solo sull'implementazione concreta, non sul metodo di un'interfaccia. Lo imposti quindi dove il codice gira effettivamente.
Sessioni: impostazioni sicure e nuovi standard
Le sessioni sono un bersaglio frequente. Tre impostazioni sono centrali: session.use_strict_mode=1 rifiuta gli ID di sessione che il server non ha generato da sé; session.cookie_httponly=1 impedisce l'accesso al cookie di sessione tramite JavaScript; session.cookie_samesite=Lax rende più difficile l'invio insieme alle richieste da siti esterni. Secondo l'RFC approvato, proprio questi tre valori diventano lo standard con PHP 8.6. Li imposti Lei stesso fino ad allora, e anche dopo in modo esplicito, perché la configurazione non dipenda dai valori predefiniti.
session.use_strict_mode = 1
session.cookie_httponly = 1
session.cookie_samesite = Lax
session.cookie_secure = 1
Altro in Mettere in sicurezza le sessioni in PHP.
Che cosa le funzioni integrate non garantiscono
Il progetto PHP è chiaro nella propria politica di sicurezza: PHP non è una sandbox. Gli aggiramenti di open_basedir o disable_functions, gli input dannosi passati a unserialize() e gli argomenti non controllati passati a funzioni come mysqli_query() non sono considerati vulnerabilità di PHP. Per i gestori significa: queste impostazioni sono un utile rafforzamento, ma non un confine di sicurezza, e unserialize() non ha nulla a che fare con dati esterni.
Il secondo punto riguarda PHP2Shell. CVE-2026-109618 e CVE-2026-109619 consentono, secondo php.net, l'esecuzione di codice prima o durante l'esecuzione della Sua applicazione; con mod_php è stato dimostrato un exploit prima ancora che venga eseguito il codice dell'applicazione. Nessuna funzione nel Suo codice può intercettarlo. Programmazione sicura e versione di PHP aggiornata sono due obblighi distinti, e devono essere rispettati entrambi.
Come aiuta concretamente PHP SOS?
Nell'audit di sicurezza per applicazioni PHP verifichiamo in modo mirato:
- Gestione di password e token: vengono usate
password_hash()erandom_bytes(), o ci sono soluzioni fatte in casa? - Output e query: dove finiscono input senza filtro in HTML, SQL o comandi di shell?
- Configurazione delle sessioni: sono impostati Strict Mode, HttpOnly, SameSite e Secure, e non sono sovrascrivibili?
- Esecuzione: gira una versione di PHP supportata con le correzioni del 21/10/2026?
Domande frequenti
Come si memorizzano correttamente le password in PHP?
Con password_hash() e PASSWORD_DEFAULT; la verifica si fa con password_verify(). Secondo il manuale la colonna del database dovrebbe poter contenere fino a 255 caratteri, perché l'algoritmo predefinito potrà cambiare in futuro.
rand() è adatta per i token?
No. Per token, chiavi e link per le password vanno usate random_bytes() o random_int(). Secondo il manuale forniscono valori casuali crittograficamente sicuri.
Da quando Sodium è incluso in PHP?
L'estensione Sodium per la crittografia moderna fa parte di PHP dalla versione 7.2.0. Le versioni precedenti potevano aggiungerla solo tramite PECL.
Queste funzioni proteggono da PHP2Shell?
No. Proteggono dagli errori nella Sua applicazione. PHP2Shell si trova nell'interprete stesso e si chiude solo con un aggiornamento di PHP, seguito dal riavvio di tutti i processi PHP.
Gli standard delle sessioni cambiano in PHP 8.6?
Sì, secondo l'RFC approvato session.use_strict_mode e session.cookie_httponly vengono attivati per impostazione predefinita e session.cookie_samesite viene impostato su Lax. Le configurazioni esistenti dovrebbe comunque impostarle Lei stesso in modo esplicito.