Hashing: cosa significa e perché è importante

Cos'è l'hashing e perché è importante non soltanto per la sicurezza informatica ma anche in un ampio ventaglio di applicazioni.

Gli sviluppatori utilizzano le funzioni di hashing ogni giorno. A livello di database per ottimizzare le query, nelle strutture di dati per rendere le cose più veloci, nell’ambito della sicurezza per mantenere i dati riservati. Anche gli utenti normali, tuttavia, hanno continuamente a che fare con i meccanismi di hashing. In un modo o nell’altro, quasi ogni interazione con la tecnologia moderna coinvolge l’utilizzo di funzioni hash. Questi funzioni sono insomma fondamentali e si trovano praticamente ovunque.

Hashing: cos’è e come funziona

Il termine “hashing” si riferisce a una tecnica matematica o a un algoritmo che acquisisce in input una quantità di dati di qualsiasi dimensione per produrre una stringa di lunghezza fissa, chiamata “hash value” o “hash code“. L’hashing è un processo unidirezionale, il che significa che è facile calcolare l’hash di un dato, ma è computazionalmente difficile o quasi impossibile risalire ai dati originali a partire dall’hash. Si dice anche che la funzione hash non è invertibile: quando ciò dovesse accadere, l’algoritmo di hashing utilizzato viene dichiarato insicuro.

Richiamando una funzione hash con uguale input, essa restituisce sempre lo stesso output. L’output, inoltre, è ricompreso in un intervallo ben preciso, all’interno della quale la funzione hash si muove.

Poiché l’input può essere qualsiasi stringa, ma il valore restituito rientra in un intervallo conosciuto, è possibile che due input diversi restituiscano lo stesso output. Questa situazione è chiamata collisione: le buone funzioni hash cercano di ridurre al minimo il numero di collisioni.

Dove e come si usano le funzioni hash nella sicurezza informatica

Nella sicurezza informatica, il termine hashing si riferisce a una tecnica crittografica che trasforma una quantità di dati di qualsiasi dimensione in una stringa di lunghezza fissa, chiamata appunto hash. La funzione hash genera un valore unico e caratteristico, che funziona come una sorta di impronta digitale dei dati originali. L’hashing è importante per diversi motivi. Li riassumiamo di seguito.

Verifica dell’integrità dei dati

L’hashing viene utilizzato per verificare se i dati sono stati modificati o alterati in qualsiasi modo durante il loro trasferimento o memorizzazione. Conoscendo l’hash dei dati originali e ricalcolandoli dopo l’invio o il salvataggio delle informazioni, è possibile confrontare i due valori hash per determinare se i dati sono rimasti intatti o se fossero stati manomessi.

Sicurezza delle password

Quando si memorizzano le password degli utenti in un database, è fondamentale non salvarle come testo normale (“in chiaro”). In caso di eventuali violazioni di sicurezza o a margine di un comportamento inidoneo da parte di dipendenti infedeli, la password di ciascun utente risulta esposta. Con tutte le spiacevoli conseguenze del caso. Ciò che va fatto, invece, è calcolare l’hash delle password con un algoritmo di hashing sicuro quindi memorizzare solo l’hash nel database. In questo modo, anche se il database venisse compromesso, gli  aggressori non possono risalire alle password originali a partire dai valori hash. Abbiamo visto come i siti Web conservano le password citando alcuni casi in cui i dati sono salvati in forma non sicura, senza usare l’hashing.

Verifica dell’autenticità

Gli hash aiutano anche a verificare l’autenticità dei dati. Ad esempio, quando si scarica un file da Internet, si può confrontare l’hash fornito separatamente con quello calcolato a partire dall’oggetto scaricato in locale. Se i due valori hash corrispondono, si può essere ragionevolmente sicuri che il file sia autentico e non sia stato alterato durante il download. Si immagini di scaricare ad esempio l’immagine ISO di Windows 11. Dalla pagina di download Microsoft, sappiamo che l’hash SHA-256 del file ISO in versione italiana è il seguente (cliccare su Verifica il tuo download):

C5D427329B9ECB139BCD0EECBB69B0C1E03726C12F514EF5D389EC20E5C35DE2

È possibile calcolare l’hash del file con Windows senza usare programmi aggiuntivi. Se il valore hash calcolato da Windows corrisponde con quello fornito da Microsoft, significa che il file ISO di Windows 11 è conforme con l’originale. Ovvero con la copia conservata sui server Microsoft. La stessa operazione può essere replicata per qualunque altro file.

Distribuzione delle chiavi crittografiche

Nella crittografia asimmetrica, l’hashing viene utilizzato per creare un’impronta digitale di una chiave crittografica pubblica. Questo consente di distribuire le chiavi in modo sicuro e verificare che la chiave ricevuta non sia stata alterata o sostituita da un utente malintenzionato.

Esistono diversi algoritmi di hashing crittografici ampiamente utilizzati, come MD5, SHA-1, SHA-256, SHA-512 che vengono utilizzati per calcolare gli hash di dati riservati e per la generazione di chiavi crittografiche.

Hashing: altri utilizzi comuni

L’hashing viene utilizzato in diverse applicazioni oltre alla sicurezza informatica. Ad esempio per implementare strutture dati come tabelle hash o mappe hash. Esse aiutano ad archiviare, recuperare e cercare dati in modo efficiente utilizzando gli hash come chiavi di accesso.

Gli hash sono utili anche ai fini del controllo dei duplicati. La funzione hash unidirezionale può essere infatti sfruttata per identificare doppioni o confrontare grandi quantità di dati in modo rapido ed efficiente.

Come accennato in precedenza, inoltre nella crittografia a chiave pubblica, l’hashing viene utilizzato per creare un’impronta digitale di un messaggio o di un documento. Questa impronta digitale viene quindi crittografata con una chiave privata per creare una firma digitale, che può essere verificata utilizzando la chiave pubblica corrispondente.

Caratteristiche delle buone funzioni hash

Le buone funzioni hash presentano alcune caratteristiche desiderabili: esse fanno sì che il corrispondente algoritmo sia considerabile come affidabile, efficiente e sicuro.

Come abbiamo evidenziato in precedenza, innanzi tutto, una funzione hash dovrebbe produrre valori unici in ouput a fronte di input diversi. La probabilità delle collisioni dovrebbe cioè essere ridotta al minimo, scongiurando le situazioni in cui due input differenti producono lo stesso valore hash. Una scarsa resistenza alle collisioni porta inevitabilmente a dichiarare un algoritmo come insicuro e non più affidabile. Allo stesso modo, una buona funzione hash deve rendere computazionalmente difficile o impossibile risalire ai dati originali a partire dall’hash (resistenza alle inversioni).

Mentre l’algoritmo MD5 è da tempo considerato insicuro, nel 2017 Google ha dichiarato SHA-1 non sicuro confermando delle collisioni; SHA-256 è invece ad oggi valutato come un buon punto riferimento. In un altro articolo abbiamo visto come recuperare le password in chiaro, servendosi di un’attività di password cracking con John The Ripper.

Gli hash prodotti, inoltre, dovrebbero essere distribuiti in modo casuale e uniforme all’interno dello spazio di output. Questo permette di evitare l’aggregazione su aree specifiche o la generazione preferenziale di un ventaglio di valori. Una piccola modifica ai dati di input dovrebbe portare alla generazione di un hash completamente diverso.

In generale, comunque, le funzioni hash devono essere efficienti da calcolare. Devono richiedere un tempo ragionevole per calcolare l’hash dei dati di input, indipendentemente dalla dimensione dei dati forniti in ingresso, e devono fornire un valore in output di lunghezza prefissata.

L’effetto valanga

Si chiama effetto valanga (“the avalanche effect“) un aspetto delle procedure di hashing al quale abbiamo brevemente fatto riferimento in precedenza. L’espressione si riferisce al numero di bit nell’output che cambiano alla modifica di un singolo bit nell’input. Per dire che una funzione hash ha un buon effetto valanga, un singolo “bit flip” (alterazione del valore del singolo bit) in input dovrebbe comportare modifiche su una media del 50% dei bit in output.

Quando piccoli cambiamenti nell’input si traducono in piccoli cambiamenti nell’output, si creano dei “modelli” o pattern. Questi ultimi indicano una scarsa distribuzione degli hash nello spazio di output e sono spia di un più elevato tasso di collisioni.

La dimostrazione pubblicata in questa pagina prende in esame la funzione hash non crittografica murmur3. Progettata da Austin Appleby e utilizzata in diverse applicazioni, murmur3 è veloce ed efficiente: genera un valore hash di 128 bit a partire da un input di dati arbitrari. Piccole modifiche ai dati in input producono un valore hash completamente diverso, riducendo così al minimo le collisioni.

Credit immagine in apertura: iStock.com/Olivier Le Moal

Ti consigliamo anche

Link copiato negli appunti