Il caricamento sicuro di file in PHP non consiste nell'accettare un modulo e spostare un file sul server. Un allegato può trasformarsi in un vettore di esecuzione, una fuga di informazioni, un carico che esaurisce le risorse o un documento inaccessibile quando il processo di business ne ha bisogno. La progettazione deve coprire l'intero ciclo: ricezione, validazione, archiviazione, elaborazione, autorizzazione di accesso, audit ed eliminazione.
Definire il contratto di business prima di accettare file

Il primo controllo non è tecnico: consiste nel limitare quale esigenza risolve ciascun allegato. Un documento di identità, una fattura e un'immagine del profilo hanno formati, proprietari, periodi di conservazione e permessi di consultazione diversi. Raggrupparli sotto un'opzione generica di «carica file» rende difficile applicare controlli adeguati.
Per ogni tipo documentale, definisci un contratto esplicito:
- Quali formati sono necessari e quali sono esclusi.
- Dimensione massima, numero massimo di allegati per operazione e quota cumulativa per account o pratica.
- Chi può caricarlo, in quale stato del processo e se può sostituirlo o eliminarlo.
- Quale validazione automatica e quale revisione umana richiede.
- Chi può visualizzarlo, scaricarlo o richiederne una nuova versione.
- Per quanto tempo viene conservato e quale evento ne attiva l'eliminazione.
Questo contratto evita di accettare file «per ogni evenienza». Consente inoltre di distinguere un errore di validazione, che l'utente può correggere, da una restrizione di business, come tentare di allegare un documento quando la pratica è già chiusa.
Perché estensione e tipo dichiarato non bastano
L'estensione del nome originale e il tipo inviato in $_FILES['type'] sono dati forniti dal client. Servono come informazioni ausiliarie dell'interfaccia, ma non provano il contenuto. Rinominare un file è banale e un client può inviare qualsiasi header HTTP.
La validazione tecnica deve usare una difesa a più livelli. In PHP, rileva il tipo a partire dai byte ricevuti con meccanismi come finfo; quindi, applica validatori specifici del formato quando il rischio o l'uso lo richiedono. Per un'immagine da visualizzare, non basta identificarla come immagine: è opportuno decodificarla mediante una libreria adeguata e generare una nuova rappresentazione. Per un PDF o un documento Office, valida la struttura prevista con strumenti specializzati in un ambiente isolato.
Una allowlist è più sicura di una blocklist. Se il caso d'uso ammette JPEG e PNG, rifiuta tutto il resto invece di tentare di elencare i formati pericolosi. I file compressi richiedono un controllo aggiuntivo: un limite alla dimensione compressa non limita l'espansione durante la decompressione. Stabilisci limiti per dimensione espansa, numero di entry, profondità di annidamento e tempo di analisi.
Anche i nomi non sono affidabili. Non usarli come percorso, identificatore o nome fisico. Sequenze come ../, caratteri di controllo, doppie estensioni e collisioni di nomi devono perdere rilevanza perché il sistema genera il proprio identificatore opaco.
Ricezione controllata e gestione degli errori parziali
Prima di elaborare il contenuto, limita la superficie di input. Configura limiti coerenti in PHP, nel server web e nel reverse proxy. Se il proxy accetta 100 MB ma PHP ne ammette 10 MB, il comportamento sarà confuso; se PHP consente più del previsto, un attaccante può consumare memoria, spazio temporaneo su disco o connessioni di lavoro.
Controlla esplicitamente la dimensione individuale, il totale della richiesta, il numero di file e la durata del caricamento. Verifica il codice di errore di ogni elemento di $_FILES, accertati che provenga da un caricamento HTTP e tratta ogni allegato come un'unità indipendente. In un'operazione multipla, decidi in anticipo se il risultato è atomico o parziale. Se sono accettati risultati parziali, la risposta deve indicare con precisione quale file è stato ricevuto, quale è stato rifiutato e perché, senza rivelare dettagli interni del server.
Non elaborare un file direttamente da un percorso controllato dalla richiesta né confidare sul fatto che un caricamento interrotto sia innocuo. I temporanei incompleti devono essere puliti e i tentativi ripetuti devono essere idempotenti quando il prodotto li supporta. Un token di operazione o una chiave di idempotenza evita di creare più allegati equivalenti dopo ritrasmissioni di rete.
Archiviazione privata, quarantena ed elaborazione
I binari non devono trovarsi nella directory pubblica dell'applicazione. Archiviali in storage privato, con credenziali a privilegio minimo, e associa ogni oggetto a un identificatore interno generato dal sistema. Il database può conservare metadati quali proprietario, contesto di business, tipo rilevato, dimensione, impronta crittografica, stato, date e policy di conservazione. Evita di salvare dati personali non necessari nel nome o nei log operativi.
Un flusso robusto separa la ricezione dalla disponibilità:
- L'applicazione riceve il file e crea un record nello stato
pendenteoin_quarantena. - Il binario viene depositato in una posizione non accessibile per i download.
- Un processo asincrono esegue analisi antimalware, validazione approfondita, trasformazione o estrazione consentita.
- Il risultato passa a
disponibile,rifiutatoorichiede_revisione. - L'interfaccia mostra lo stato operativo senza fingere che un caricamento sia già utilizzabile.
Le code riducono il tempo di risposta, ma introducono errori propri: job duplicati, messaggi ritardati e processori non disponibili. Progetta task idempotenti, limiti di tentativi, avvisi per elementi bloccati e un percorso di rielaborazione controllato. Se l'analisi non è disponibile, l'alternativa sicura è solitamente mantenere l'allegato in quarantena, non pubblicarlo.
Autorizzare ogni download e distribuire contenuto senza eseguirlo
Il fatto che qualcuno conosca un identificatore non gli concede l'accesso. Ogni download deve verificare l'identità autenticata, la sua relazione attuale con la risorsa e il contesto di business: appartenenza a un'organizzazione, assegnazione alla pratica, ruolo vigente, stato del documento e restrizioni temporali. Non riutilizzare l'autorizzazione esistente al momento del caricamento del file; i permessi potrebbero essere stati revocati in seguito.
Il download deve passare attraverso un controller che applica questa decisione prima di leggere o delegare l'oggetto. Le URL firmate possono essere utili per la distribuzione da storage esterno, ma richiedono ambito limitato, scadenza breve e controlli che impediscano di emetterle per risorse non autorizzate.
Distribuisci con cautela i tipi attivi. Per documenti non destinati al rendering nel browser, usa Content-Disposition: attachment. Imposta il tipo di contenuto in base al tipo validato, non all'estensione, e aggiungi X-Content-Type-Options: nosniff. Un'anteprima non è un semplice download incorporato: deve usare rappresentazioni trasformate, isolare contenuto potenzialmente attivo ed evitare di rivelare percorsi interni.
Audit, ripristino e test prima della produzione

Registra gli eventi rilevanti: creazione, sostituzione, cambio di stato, download, eliminazione, errore di analisi e modifica dei permessi. Il log deve contenere attore, momento, risorsa e risultato, ma non deve archiviare il binario né dati sensibili duplicati. Proteggi questi eventi dalle alterazioni e definisci chi può consultarli.
Il ripristino richiede di sapere cosa accade se si guasta lo storage, il database o il processore. Non contrassegnare un documento come disponibile finché il binario e i suoi metadati non sono coerenti. Progetta task di riconciliazione per rilevare record senza oggetto, oggetti orfani ed elementi che restano troppo a lungo in quarantena.
Checklist di rilascio
- I formati consentiti rispondono a un caso d'uso documentato e sono validati in base al contenuto.
- Esistono limiti di dimensione, quantità, tempo ed espansione dei file compressi.
- I nomi originali non determinano percorsi né nomi fisici.
- I binari sono archiviati fuori dalla directory pubblica e passano dalla quarantena quando necessario.
- Il download rivaluta l'autorizzazione e non espone percorsi interni.
- Vengono testati file malformati, duplicati, caricamenti interrotti, permessi revocati e guasti dello storage.
- Esiste monitoraggio di rifiuti, job bloccati, errori di distribuzione e capacità consumata.
- Le policy di conservazione, cancellazione e audit hanno un responsabile operativo.
Trasformare un caricamento in un flusso con stati e controlli può sembrare più costoso rispetto all'uso di una directory di upload. Tuttavia, riduce le decisioni improvvisate quando compare un file sospetto, una richiesta di accesso o un'interruzione operativa. Questa tracciabilità fa parte del prodotto, non è un'aggiunta successiva.



