OWASP Top 10 2025: cosa è cambiato e come adattare le difese per applicazioni PHP

OWASP Top 10 2025: cosa è cambiato e come adattare le difese per applicazioni PHP

Nel 2025 l'OWASP Top 10 ha pubblicato l'aggiornamento della classifica delle dieci vulnerabilità più critiche per le applicazioni web - il primo aggiornamento significativo dal 2021. In parallelo, ho condotto audit di sicurezza su 12 applicazioni PHP di clienti PMI (otto su Laravel, due su Symfony, due su codebase custom senza framework) utilizzando il nuovo framework come riferimento per la valutazione. I risultati sono stati istruttivi: i pattern di vulnerabilità del 2025 sono diversi da quelli di cinque anni fa, non perché le vulnerabilità classiche siano scomparse (SQL injection e XSS sono ancora presenti nel 30% delle applicazioni auditate), ma perché nuove categorie di rischio - in particolare l'insecure design, le dipendenze vulnerabili nella supply chain e la sicurezza del codice generato da AI - sono salite nella classifica riflettendo la realtà del panorama di attacco attuale.

L'aggiornamento 2025 non è una semplice revisione dell'ordine delle categorie: introduce cambiamenti strutturali che hanno impatto diretto su come uno sviluppatore PHP dovrebbe valutare la sicurezza del proprio codice. Le categorie che erano separate nel 2021 sono state consolidate dove i confini erano artificiali, e nuove categorie sono state aggiunte per riflettere rischi che nel 2021 erano emergenti e che nel 2025 sono diventati dominanti. Per chi gestisce applicazioni PHP in produzione per PMI italiane - il contesto in cui lavoro quotidianamente - capire questi cambiamenti e tradurli in azioni concrete è la differenza tra un'applicazione che resiste a un audit e una che mostra vulnerabilità critiche alla prima ispezione.

Quali sono i cambiamenti più significativi dell'OWASP Top 10 2025 rispetto al 2021?

La novità più rilevante per gli sviluppatori PHP è la prominenza crescente della categoria Insecure Design (A04:2021, ora consolidata con peso maggiore). Non si tratta di bug nel codice - si tratta di decisioni architetturali che rendono l'applicazione intrinsecamente vulnerabile indipendentemente dalla qualità dell'implementazione. Un esempio che ho trovato in tre delle 12 applicazioni auditate: il flusso di reset password che invia un token via email con validità di 72 ore, senza invalidazione del token precedente quando ne viene richiesto uno nuovo, senza rate limiting sulle richieste di reset, e senza log delle richieste per audit. Il codice PHP è perfetto - nessun bug, nessuna SQL injection, nessun XSS. Ma il design del flusso è insicuro: un attaccante può richiedere centinaia di token di reset per un singolo account, ciascuno valido per 72 ore, e provare a usarli tutti via brute force. La fix non è nel codice - è nel design: token con validità di 15 minuti, invalidazione automatica dei token precedenti alla richiesta di uno nuovo, rate limiting a 3 richieste per ora per email, e logging di ogni richiesta di reset con IP e user agent.

La seconda novità significativa è la maggiore enfasi sulla sicurezza della supply chain software - le dipendenze del tuo composer.json e del tuo package.json. L'OWASP ha consolidato i rischi legati a componenti vulnerabili e outdated (A06:2021) con un'attenzione specifica al fenomeno del typosquatting, della dependency confusion e delle vulnerabilità zero-day in librerie ampiamente diffuse. Nelle 12 applicazioni auditate, 9 avevano almeno una dipendenza Composer con una vulnerabilità nota non patchata - e in 4 casi la vulnerabilità era classificata come critica (CVSS 9.0+). Nessuna delle 12 applicazioni eseguiva composer audit nella pipeline CI/CD. Ho descritto le contromisure specifiche per la supply chain PHP nel mio articolo sulla sicurezza della supply chain con Composer per Laravel e Symfony, che copre il pinning delle versioni, l'audit automatizzato e la protezione contro i pacchetti malevoli.

Nel mio profilo professionale trovi il dettaglio dell'esperienza che porto negli audit OWASP per applicazioni PHP - un'area dove la conoscenza offensiva (sapere come un attaccante sfrutterebbe la vulnerabilità) è il prerequisito per una valutazione difensiva efficace.

Broken access control: la vulnerabilità numero uno che nessuno testa

Broken Access Control è al primo posto dell'OWASP Top 10 dal 2021, e nel 2025 rimane la categoria con il tasso di incidenza più alto - presente nel 94% delle applicazioni testate secondo i dati aggregati di OWASP. Nelle 12 applicazioni PHP che ho auditato, 8 avevano almeno un difetto di controllo degli accessi. Il pattern più comune non è l'assenza di autenticazione (tutti usavano Laravel Auth o Symfony Security), ma l'insufficienza dell'autorizzazione: l'utente è autenticato, ma può accedere a risorse che non gli appartengono modificando un parametro nell'URL o nel body della richiesta.

L'esempio classico che trovo in ogni altro progetto Laravel: un endpoint GET /api/ordini/{id} che verifica che l'utente sia autenticato ma non verifica che l'ordine {id} appartenga all'utente autenticato. Qualsiasi utente loggato può accedere agli ordini di qualsiasi altro utente semplicemente iterando gli ID. La fix è un'autorizzazione esplicita - una Policy Laravel o un Gate - che verifica la proprietà della risorsa ad ogni richiesta. Il test che scrivo per verificare è semplice e dovrebbe essere in ogni suite:

// Test di autorizzazione: un utente non può vedere gli ordini altrui
public function test_utente_non_può_accedere_ordini_altrui(): void
{
    $alice = User::factory()->create();
    $bob = User::factory()->create();
    $ordine_di_bob = Ordine::factory()->create(['user_id' => $bob->id]);

    $this->actingAs($alice)
        ->getJson("/api/ordini/{$ordine_di_bob->id}")
        ->assertForbidden(); // 403, non 200
}

Se questo test passa con status 200 nella tua applicazione, hai un difetto di broken access control. La frequenza con cui trovo questo pattern nelle applicazioni PMI è allarmante: 8 su 12, il 67%. Non per incompetenza degli sviluppatori, ma perché l'autorizzazione è una preoccupazione che viene tipicamente affrontata "dopo" - prima si fa funzionare l'endpoint, poi si aggiungono i controlli. E quel "poi" non arriva mai.

Injection: ancora presente, ma con vettori nuovi

SQL injection è al terzo posto della classifica 2025, e contrariamente a quanto molti pensano, non è un problema risolto. Nelle 12 applicazioni auditate, 4 avevano almeno un endpoint vulnerabile a injection - non nelle query Eloquent standard (che usano prepared statement di default), ma in tre contesti specifici che sfuggono alla protezione automatica del framework.

Il primo contesto è le query raw: DB::select("SELECT * FROM products WHERE category = '$category'") con concatenazione diretta dell'input utente. Il secondo è le espressioni whereRaw e orderByRaw usate per costruire ordinamenti dinamici: ->orderByRaw($request->sort_by) dove sort_by viene dall'URL e non è validato - un attaccante può iniettare id; DROP TABLE users-- e il prepared statement non protegge perché l'espressione è passata come SQL grezzo. Il terzo contesto, nuovo nel 2025, è il codice generato da AI (Copilot, ChatGPT) che produce query con concatenazione di stringhe perché i modelli sono stati addestrati su codice che usava quel pattern - un rischio emergente che l'OWASP 2025 affronta esplicitamente nella sezione sulla sicurezza del codice AI-assisted.

La remediation per le query raw è sempre la stessa: prepared statement con binding. Per le espressioni orderByRaw, la soluzione è una whitelist dei campi ammessi nel controller, validata con una regola in: nel FormRequest. Per il codice generato da AI, la soluzione è una review di sicurezza esplicita di ogni query generata dall'LLM prima del merge - un pattern che ho integrato nel bot di code review automatizzato con Claude API nelle pipeline GitHub.

Server-Side Request Forgery (SSRF): il rischio che sale nella classifica

SSRF è la vulnerabilità che ha avuto la crescita più significativa nella classifica 2025. Il pattern è: l'applicazione accetta un URL dall'utente e fa una richiesta HTTP a quell'URL - per esempio, per scaricare un'immagine da un URL esterno, per verificare un webhook, o per fare una preview di un link. Se l'URL non viene validato rigorosamente, l'attaccante può passare un URL interno (http://169.254.169.254/ per i metadata cloud, http://localhost:6379/ per Redis, http://internal-api:8080/admin/) e l'applicazione fa la richiesta per conto dell'attaccante, accedendo a risorse interne che non dovrebbero essere raggiungibili dall'esterno.

Nelle applicazioni Laravel, il client HTTP integrato (Http::get($url)) non ha protezioni SSRF di default. La fix è un middleware di validazione che blocca le richieste verso IP privati (RFC 1918), localhost, link-local (169.254.x.x), e IP interni della rete cloud prima di eseguire la richiesta. Ho trovato vulnerabilità SSRF in 3 delle 12 applicazioni auditate - tutte in endpoint di upload di immagini da URL esterno.

Il piano d'azione: come verificare la tua applicazione contro l'OWASP 2025

Per ogni categoria dell'OWASP Top 10 2025, ho prodotto per i miei clienti un documento di verifica con test specifici da eseguire - non un audit completo (che richiede competenze offensive specializzate), ma un primo assessment che uno sviluppatore PHP senior può fare autonomamente. I punti di verifica prioritari sono: controllare che ogni endpoint API abbia una Policy o un Gate di autorizzazione (non solo autenticazione); eseguire composer audit e risolvere tutte le vulnerabilità critiche e alte; verificare che tutte le query con whereRaw, orderByRaw e DB::select usino binding o whitelist; testare gli endpoint che accettano URL dall'utente con URL locali e interni; controllare che i flussi di autenticazione (login, reset password, registrazione) abbiano rate limiting e logging; verificare che le risposte API non espongano più dati di quelli necessari (no stack trace, no SQL in produzione, no .env accessibile via web).

Cryptographic failures e security misconfiguration: due categorie che sembrano banali ma colpiscono duro

I cryptographic failures (A02) e le security misconfiguration (A05) sono le categorie che i team tendono a sottovalutare perché sembrano "cose di base" - e proprio per questo sono le più frequenti. Nelle 12 applicazioni auditate, 6 avevano almeno un problema crittografico significativo: password hashate con MD5 o SHA-1 (algoritmi considerati insicuri dal 2017), token di sessione con entropia insufficiente generati con rand() invece di random_bytes(), e comunicazioni tra servizi interni su HTTP invece che HTTPS all'interno della stessa rete privata (esponendo i dati a intercettazione da parte di qualsiasi processo sulla stessa VLAN). Le misconfiguration erano ancora più diffuse: 10 delle 12 applicazioni avevano APP_DEBUG=true in almeno un ambiente raggiungibile dall'esterno (staging senza autenticazione), 7 avevano il file .env accessibile via web (navigando a https://dominio.it/.env), e 5 avevano stack trace dettagliati nelle risposte di errore JSON delle API in produzione - stack trace che esponevano path del filesystem, versioni dei pacchetti, nomi delle tabelle del database e credenziali parziali nelle stringhe di connessione.

La fix per i problemi crittografici è tecnica e immediata: migrare gli hash delle password a bcrypt o Argon2id (Laravel usa bcrypt di default, ma molte applicazioni legacy hanno migrazioni incomplete con hash MD5 residui nel database), sostituire rand() e mt_rand() con random_int() e random_bytes() per ogni uso crittografico, e configurare TLS anche per le comunicazioni interne tra servizi. La fix per le misconfiguration è operativa: un'aggiunta al .htaccess o alla configurazione Nginx che blocca l'accesso ai file dot, la verifica che APP_DEBUG=false in tutti gli ambienti raggiungibili dall'esterno, e un middleware che sanitizza le risposte di errore prima di inviarle al client in produzione. Ciascuna di queste fix richiede meno di 30 minuti - il che rende l'assenza di queste misure ancora più inspiegabile quando la si scopre durante un audit.

Ho descritto le misure di hardening specifiche per applicazioni Laravel e Symfony nel mio articolo sulla checklist di hardening NIS2-ready in 14 giorni, che copre molti dei punti di verifica OWASP con istruzioni operative passo-passo. L'audit di sicurezza non è un evento una tantum - è un processo continuo che dovrebbe essere integrato nel workflow di sviluppo, nella pipeline CI/CD e nelle review del codice. Se la tua applicazione PHP non è mai stata auditata contro l'OWASP Top 10, contattami per un assessment di sicurezza: in tre giornate di lavoro testo ogni categoria con payload reali, documento le vulnerabilità trovate con severity e remediation, e produciamo un piano di correzione prioritizzato per risolvere i problemi critici nelle prime due settimane.

Ultima modifica: