Sviluppo del software
Attacchi temporali in PHP: Un esempio pratico: perché `hash_equals()` è importante
Vuoi un esempio realistico di attacco temporizzato ai token API in Wordpress/Laravel/PHP? Ne parliamo qui, includendo suggerimenti e misure di best practice contro gli attacchi temporali.
Molti sviluppatori si affidano al semplice confronto con === o == quando controllano chiavi API, token o altre stringhe segrete. A prima vista sembra ragionevole, ma c'è un problema: le differenze di tempistica nel confronto possono essere sfruttate dagli aggressori.
Questo articolo descrive un esempio realistico di come funziona concettualmente un attacco temporizzato.
Lo scenario reale (esempio semplificato)
Immaginiamo che un microservizio interno accetti richieste con un token di parametro di query e lo confronti con un token API di GitHub memorizzato nell'ambiente.
Codice insicuro (semplificato):
$expected = getenv('GITHUB_API_TOKEN');$provided = $_GET['token'] ?? '';if ($provided === $expected) { } PHP
Spiegherò perché questo è un problema nella prossima sezione.
Come funziona un attacco temporizzato?
Se l'implementazione del confronto dei token confronta carattere per carattere e si interrompe immediatamente al primo errore, una richiesta con il primo carattere corretto richiederà in media un po' più di tempo.
Un primo carattere corretto comporta quindi un tempo di elaborazione leggermente più lungo rispetto a un primo carattere errato. Lo stesso vale per il secondo carattere e così via.
Un attaccante sfrutta questa situazione testando tutti i caratteri possibili per ogni posizione, misurando i tempi di risposta molto spesso e analizzandoli statisticamente. Il carattere con il tempo medio/proporzionalmente più lungo è probabilmente quello corretto. In questo modo, il token viene ricostruito passo dopo passo.
Perché hash_equals() è la scelta giusta
PHP offre una funzione di confronto delle stringhe a tempo costante con hash_equals(). Garantisce che il tempo di esecuzione del confronto non dipenda dai prefissi comuni, a patto che le due stringhe abbiano la stessa lunghezza.
Alternativa sicura (per Laravel, PHP, Wordpress):
$expected = getenv('GITHUB_API_TOKEN'); $provided = $_GET['token'] ?? '';if (hash_equals($expected, $provided)) { } PHP
Nota: hash_equals() è "indipendente dal tempo" solo se le lunghezze sono uguali. È buona norma progettare i token in modo che la lunghezza sia costante (ad esempio HMAC, UUID a lunghezza fissa o stringhe Base64 casuali a lunghezza fissa).
Lo sapevi? Solo l'UUID-V4 è completamente generato in modo casuale e per questo viene spesso utilizzato per i token di sicurezza. Poiché non contiene informazioni relative all'ora o al dispositivo, offre un alto livello di imprevedibilità e quindi protegge dagli attacchi basati su schemi o previsioni. Proprio per questo l'UUID-V4 è la scelta preferita quando si tratta di identificatori sicuri e difficili da indovinare.
Misure di difesa aggiuntive - oltre a hash_equals()
- Lunghezza costante del token
Utilizza token con una lunghezza fissa, ad esempio UUID-V4. Se un aggressore indovina la lunghezza, questo è meno utile se i caratteri stessi sono sicuri.
- Limitazione della velocità
Limita le richieste per IP o per account. Gli attacchi temporali richiedono molte misurazioni; la limitazione della velocità aumenta notevolmente lo sforzo e i costi per l'attaccante.
- Registrazione e monitoraggio
Riconosci gli schemi insoliti (molti tentativi di token, variazione sistematica di alcuni parametri) e reagisci automaticamente.
- Sale / HMAC / Firme
Usa token firmati (HMAC con chiave segreta) o token OAuth invece di confrontare apertamente chiavi statiche grezze.
- TLS/HTTPS
La crittografia protegge i canali di comunicazione - anche se non impedisce gli attacchi temporali agli interni del server, è un requisito fondamentale.
- Rotazione dei token
La breve durata dei token riduce i vantaggi di un token compromesso.
Conclusioni
Gli attacchi temporali non sono un problema puramente teorico: sono stati studiati nella pratica e possono avere gravi conseguenze, soprattutto per gli endpoint accessibili al pubblico. La buona notizia: per gli sviluppatori PHP/Laravel/Wordpress, la prima contromisura è molto semplice:
- Sostituire i confronti diretti di stringhe sensibili con
hash_equals().
- Garantisci una lunghezza costante dei token, una limitazione della velocità, la registrazione e una gestione sicura dei token.