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 →

Prevenire il Server-Side Request Forgery (SSRF) in PHP

Come gli sviluppatori impediscono che un'applicazione PHP interroghi sistemi interni per conto di estranei: liste consentite, limitazione dei protocolli, verifica dell'indirizzo risolto e limiti nella rete.

Stato 6 min di letturaSviluppo sicuro

In breve: l'SSRF in PHP si previene facendo sì che la sua applicazione richiami solo indirizzi presenti in una lista consentita fissa, esclusivamente via HTTPS, senza seguire i reindirizzamenti. L'indirizzo IP risolto viene verificato rispetto agli intervalli privati e riservati e poi mantenuto fisso per la connessione. Un firewall per il traffico in uscita fa sì che i sistemi interni restino irraggiungibili anche in caso di errore nel codice.

Quando il proprio server effettua richieste per conto di estranei

Anteprime di link in una chat, importazione di un'immagine di prodotto tramite URL, webhook verso sistemi di partner, un lettore di feed nel CMS: molte applicazioni PHP richiamano indirizzi indicati da un utente. È una funzione utile e al tempo stesso una porta verso l'interno.

Nel Server-Side Request Forgery, in breve SSRF, un aggressore induce l'applicazione a inviare una richiesta a una destinazione di sua scelta. Il punto chiave: la richiesta proviene dal server stesso. Raggiunge così sistemi bloccati dall'esterno, ad esempio database, interfacce di amministrazione nella rete interna, servizi in ascolto solo su localhost o i servizi di metadati dei fornitori cloud.

Nella OWASP Top 10 del 2021 l'SSRF era una categoria a sé. Nei progetti PHP la vulnerabilità compare spesso dove qualcuno ha costruito in fretta una funzione «aggiungi immagine tramite URL».

SSRF in PHP: quali funzioni richiamano indirizzi

Non è solo cURL a richiamare indirizzi. Questi sono i punti da tenere d'occhio:

Funzione o ambito Perché è rilevante
cURL (curl_exec()) Via più frequente, molti protocolli possibili
file_get_contents(), fopen(), copy() con URL Usano wrapper URL se allow_url_fopen è attivo
getimagesize() e librerie di immagini Possono caricare file remoti
Elaborazione XML, client SOAP In certi casi caricano risorse esterne
Librerie HTTP come Guzzle Si basano su cURL o stream, stesse regole

Se la sua applicazione non ha bisogno di aprire file remoti con funzioni sui file, disattivi allow_url_fopen lato server. Un tema affine, l'inclusione di file tramite percorsi provenienti dalla richiesta, lo tratta la guida Prevenire Local e Remote File Inclusion.

La difesa in cinque passi

OWASP raccomanda una combinazione di misure che singolarmente potrebbero essere aggirate, ma insieme reggono:

  1. Lista consentita invece di URL libero: meglio ancora, l'utente sceglie solo tra destinazioni note, oppure indica soltanto un identificatore e l'applicazione costruisce da sé l'indirizzo.
  2. Consentire solo HTTPS: escludere in cURL altri protocolli come file, gopher o ftp, anche per i reindirizzamenti.
  3. Non seguire i reindirizzamenti: altrimenti un indirizzo consentito può reindirizzare a una destinazione interna.
  4. Verificare e fissare l'indirizzo risolto: risolvere l'hostname, verificare l'IP rispetto agli intervalli privati, di loopback e link-local e usare esattamente questo IP per la connessione. Altrimenti una seconda risoluzione DNS può fornire una destinazione diversa.
  5. Limitare la rete: il server web può raggiungere verso l'esterno solo le destinazioni che gli servono.

Uno schema sicuro con cURL

L'esempio seguente attua i passi da 1 a 4 per IPv4. Hostname e svolgimento sono esempi; per IPv6 valgono le stesse verifiche.

<?php
declare(strict_types=1);

function ladeVonPartner(string $url): string
{
    $teile = parse_url($url);
    if (!is_array($teile) || ($teile['scheme'] ?? '') !== 'https'
        || isset($teile['user']) || isset($teile['pass']) || isset($teile['port'])) {
        throw new InvalidArgumentException('Adresse nicht erlaubt.');
    }

    $host = strtolower($teile['host'] ?? '');
    $erlaubt = ['api.partner.example', 'bilder.partner.example'];
    if (!in_array($host, $erlaubt, true)) {
        throw new InvalidArgumentException('Ziel nicht erlaubt.');
    }

    $ip = gethostbyname($host);
    $oeffentlich = filter_var($ip, FILTER_VALIDATE_IP,
        FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
    if ($oeffentlich === false) {
        throw new RuntimeException('Ziel löst auf eine nicht erlaubte Adresse auf.');
    }

    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER  => true,
        CURLOPT_FOLLOWLOCATION  => false,
        CURLOPT_PROTOCOLS       => CURLPROTO_HTTPS,
        CURLOPT_REDIR_PROTOCOLS => CURLPROTO_HTTPS,
        CURLOPT_RESOLVE         => [$host . ':443:' . $ip],
        CURLOPT_CONNECTTIMEOUT  => 3,
        CURLOPT_TIMEOUT         => 10,
    ]);
    $antwort = curl_exec($ch);
    if ($antwort === false) {
        throw new RuntimeException('Abruf fehlgeschlagen.');
    }
    return $antwort;
}

Alcuni dettagli sono importanti. In caso di errore gethostbyname() restituisce l'hostname; la successiva verifica dell'IP lo intercetta. I flag FILTER_FLAG_NO_PRIV_RANGE e FILTER_FLAG_NO_RES_RANGE escludono secondo il manuale PHP, tra l'altro, gli intervalli 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8 e 169.254.0.0/16. Da PHP 8.2 esiste inoltre FILTER_FLAG_GLOBAL_RANGE, che ammette solo indirizzi validi a livello globale. CURLOPT_RESOLVE fa sì che cURL usi esattamente l'indirizzo verificato, mentre hostname e verifica del certificato restano invariati.

Altri due punti limitano ciò che un aggressore apprende da una vulnerabilità SSRF. Non restituisca all'utente senza filtro risposte e messaggi di errore della destinazione richiamata: già la distinzione tra «connessione rifiutata» e «timeout» rivela quali servizi interni esistano. E limiti durata e dimensione della risposta, affinché la funzione non serva a sovraccaricare il proprio server. I webhook verso indirizzi che i clienti inseriscono da sé si inviano meglio da una coda e non durante la richiesta in corso.

Importante

Se la sua applicazione deve davvero richiamare indirizzi arbitrari, ad esempio per le anteprime di link, trasferisca questa funzione in un servizio separato, senza accesso alla rete interna. Una lista consentita allora non è possibile, ma la separazione della rete diventa tanto più importante.

Il livello di rete come rete di sicurezza

Le verifiche nel codice possono avere lacune, ad esempio quando due librerie scompongono un URL in modo diverso. OWASP consiglia di trattare simili incongruenze come un rifiuto e di limitare in aggiunta a livello di rete. Un server web ha bisogno verso l'esterno di solito solo di poche destinazioni: sorgenti dei pacchetti, fornitori di pagamento e spedizione, relay di posta, determinate interfacce.

Un firewall per il traffico in uscita aiuta due volte. Ferma le richieste SSRF verso la rete interna e, dopo un'intrusione, ad esempio tramite una versione PHP non aggiornata, rende più difficile scaricare altri strumenti. Come costruire le regole lo descrive Firewall per server web: aprire solo le porte necessarie. Quali connessioni un server stabilisca davvero lo mostra Verificare le connessioni in uscita di un server.

Negli ambienti cloud rientra anche la variante rafforzata del servizio di metadati. OWASP indica per AWS il passaggio a IMDSv2 e la disattivazione di IMDSv1.

Individuare l'SSRF nel codice esistente

Un inizio rapido è la ricerca dei punti in cui le funzioni di richiamo ricevono valori dalla richiesta:

grep -rnE "(curl_init|file_get_contents|fopen|getimagesize|copy)\s*\(" src/ --include="*.php" | grep -E '\$_(GET|POST|REQUEST)|\$url'
grep -rn "CURLOPT_FOLLOWLOCATION" src/ --include="*.php"

I risultati sono incarichi di verifica. Esamini con particolare cura le funzioni usate dagli admin: importazioni, impostazioni dei webhook, controlli degli aggiornamenti dei plugin.

Si trascurano facilmente i generatori di PDF che convertono in documenti HTML con immagini o fogli di stile incorporati. Se una parte di questo HTML proviene da input dell'utente, ad esempio nelle fatture con logo a scelta libera, il generatore in certi casi richiama indirizzi stabiliti dall'utente. Verifichi lì le impostazioni per il caricamento di risorse remote e le disattivi se non servono.

Come aiuta concretamente PHP SOS?

  • Troviamo tutti i punti in cui la sua applicazione richiama indirizzi, anche in plugin e librerie.
  • Costruiamo una funzione di richiamo centrale con lista consentita, limitazione dei protocolli e verifica dell'IP.
  • Definiamo regole per il traffico in uscita e proteggiamo i servizi di metadati negli ambienti cloud.
  • Verifichiamo l'attuazione dall'esterno e documentiamo le destinazioni consentite.

Una verifica indipendente della sua applicazione è descritta in audit di sicurezza e penetration test.

Domande frequenti

Quali funzioni PHP possono essere sfruttate per l'SSRF?

Tutte quelle che richiamano un indirizzo da input dell'utente: cURL, file_get_contents e fopen con wrapper URL, funzioni per immagini e XML che caricano file remoti, nonché librerie per webhook, feed o anteprime di link.

Basta bloccare gli indirizzi IP interni?

Da solo no. OWASP definisce le liste di blocco facili da aggirare e raccomanda le liste consentite. Inoltre l'applicazione deve usare esattamente l'indirizzo che ha verificato e non deve seguire i reindirizzamenti.

Perché l'SSRF è particolarmente critico nel cloud?

I fornitori cloud mettono a disposizione delle istanze servizi interni di metadati, tramite i quali in parte si possono ottenere credenziali. Se un'applicazione può inviare richieste in quella direzione, un aggressore può raggiungere tali dati tramite essa. I fornitori offrono varianti rafforzate di questi servizi, che dovrebbero essere attivate.

A che cosa serve un firewall per il traffico in uscita?

Limita quali destinazioni il server possa raggiungere. Anche se una verifica nel codice fallisce, i sistemi interni restano allora irraggiungibili. Inoltre, dopo un'intrusione, rende più difficile scaricare codice malevolo e far uscire dati.

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