16 Oct
This post was written for the italian cybersecurity blog Cyberment and published here.
Il ruolo dell’Hashing nella cybersecurity
Alla base delle tecnologie quotidianamente più utilizzate, dalla protezione delle password all’integrità dei file, dall’autenticazione degli utenti alla crittografia delle comunicazioni, vi è l’hashing. In questo articolo spiegheremo cosa sono i codici hash, come funzionano e in che modo si inseriscono nel panorama della sicurezza informatica, nel quale giocano un ruolo fondamentale.
Codici hash e funzioni di hash
Una funzione di hash è una funzione matematica che trasforma una stringa di testo di lunghezza variabile in una nuova stringa di lunghezza fissata e del tutto indipendente dalla prima. L’output di queste funzioni è comunemente detto codice hash, digest, o semplicemente hash, mentre il processo di trasformazione della stringa è detto hashing. L’utilità delle funzioni di hash è dovuta ad alcune proprietà di queste funzioni che le rendono particolarmente interessanti per le applicazioni informatiche e, ancor più, per la sicurezza informatica.
Innanzitutto, le funzioni di hash sono funzioni matematiche non invertibili. In informatica questo si traduce in funzioni computazionalmente facili da calcolare, ma particolarmente difficili da invertire. Non è possibile, quindi, risalire al testo in input conoscendo solo l’output della funzione. È evidente fin da subito l’importanza della proprietà di irreversibilità se si pensa, ad esempio, al mantenimento di alcune password all’interno di un file o di un database. Anche in presenza di un data leakage, gli attaccanti non verrebbero a conoscenza delle password salvate nel database, ma solo dei loro hash, irreversibili e quindi inutili al fine di individuare le password.
Un’altra proprietà fondamentale delle funzioni di hash, appena accennata prima, è l’indipendenza dell’hash dal testo in input. Una funzione di hash dovrebbe sempre produrre digest sufficientemente diversi per dati in input anche molto simili. Anche questa proprietà ci è molto utile nella protezione dei dati: sarebbe molto più facile, altrimenti, associare un hash ad una data password, conoscendone una simile.
Infine, vi è la resistenza alle collisioni: data una funzione di hash, non dev’essere possibile trovare intenzionalmente due stringhe che producano lo stesso digest. Anche in questo caso, l’esempio del mantenimento delle password fornisce un utilizzo chiaro di questa proprietà: se così non fosse, sarebbe molto più facile per un attaccante risalire ad una stringa il cui digest combaci con quello della password obiettivo, piuttosto che trovare esattamente quella password.
In particolare, le proprietà appena introdotte devono essere computazionalmente intrattabili: l’unico modo per risalire sistematicamente ai dati di input, conoscendo solo i digest, è utilizzare un metodo forza bruta. Computazionalmente oneroso per stringhe da una decina di caratteri, impossibile per stringhe di lunghezza variabile.
Per chiarire quanto detto, riportiamo un esempio pratico utilizzando la funzione di hash SHA-256
:
Cyberment
:164d322d4dc351dfb35dfe1dacd6f49e67377e98e83bd62ce718a618357a5d09
cyberment
:377dc9b689869fbf9c81ce2eb7f0a6d4ca182506e814dbe9e9e9d131d7563572
.
Due stringhe di nove caratteri, del tutto uguali a meno della prima lettera maiuscola, generano due digest di sessantaquattro caratteri esadecimali, del tutto diversi tra loro. Risulta evidente che non c’è modo di ricondursi alla stringa di partenza conoscendo esclusivamente l’hash finale.
L’hashing nella Cybersecurity
Come accennato, le funzioni di hash svolgono un ruolo fondamentale nella sicurezza informatica, in più di un contesto. Di seguito riprenderemo il caso della memorizzazione delle password all’interno di un database, per poi dare una panoramica degli altri scenari in cui l’hashing si rivela necessario per la sicurezza o l’integrità di dati sensibili.
Hashing nelle password
Come abbiamo detto prima, uno degli scenari in cui l’hashing è più utilizzato – nel mondo della sicurezza informatica – è la memorizzazione delle password di sistemi o servizi che richiedono un’autenticazione all’interno di un database.
I sistemi che utilizzano questo tipo di accorgimento, memorizzano non le password all’interno del database, ma i loro hash. Nel momento in cui un utente inserisce la propria password per autenticarsi, viene ricalcolato l’hash della stessa e confrontato con quello memorizzato all’interno del database. In questo modo è possibile prevenire la perdita e diffusione di password o altri dati sensibili qualora avvenisse un data leakage. Per di più, in alcuni casi l’hashing della password previene implicitamente altri tipi di attacchi: si pensi ad esempio ad un attacco di tipo SQL injection: l’hashing del valore inserito nel campo password rende quella parte del form invulnerabile all’attacco, andando a calcolare l’hash del codice iniettato e rendendolo una stringa di testo priva di significato. Resta naturalmente di fondamentale importanza proteggere gli altri campi del form.
Nonostante gli evidenti benefici dati dal processo di hashing delle password, l’attaccante può comunque riuscire a risalire alle password, partendo dagli hash, facendo uso di attacchi a dizionario o rainbow table. Per questo motivo è fondamentale, nella memorizzazione delle password, utilizzare, oltre che l’hash, il salting.
Integrità e firma digitale
Le funzioni hash risultano utili, se non fondamentali, anche per la verifica dell’integrità di file o messaggi.
Dato che due messaggi diversi, fosse anche solo per un carattere, producono digest del tutto differenti, il calcolo dell’hash prima e dopo la trasmissione del messaggio rivelerebbe in modo inconfutabile l’avvenuta modifica – fosse questa dovuta ad errori o a manomissioni – del messaggio. Lo stesso avviene per i file: quando si vuole scaricare un file da internet è spesso disponibile il digest del file secondo un dato algoritmo di hashing. Basterà dare in pasto allo stesso algoritmo il file scaricato per renderci conto se vi sono stati problemi o manomissioni durante il download. In questo contesto, il codice hash è anche detto checksum.
Questo metodo di verifica è anche alla base di molti algoritmi di firma digitale, che utilizzano una funzione di hash per produrre il digest del documento, a sua volta crittografato con algoritmi specifici. Il destinatario, una volta decifrato il messaggio e ottenuto il digest, potrà calcolare l’hash del documento e confrontare i due digest. Se i valori corrispondono, la firma è considerata valida, confermando così l’integrità del messaggio e l’autenticità del mittente.
Algoritmi di hashing
Esistono infinite funzioni di hash, ognuno con proprietà diverse da utilizzare in contesti diversi. Gli algoritmi più diffusi e utilizzati implementano le cosiddette funzioni crittografiche di hash:
MD5: partendo da stringhe di lunghezza variabile, restituisce un digest di 128 bit. È tra gli algoritmi più utilizzati per la verifica dell’integrità di file e messaggi, utilizzato anche per molte distribuzioni Linux e MS Windows. Il suo utilizzo è tuttavia sconsigliato, in quanto sono stati studiati diversi algoritmi capaci di generare velocemente collisioni.
SHA-1: il nome è la sigla di “Secure Hash Algorithm”, produce un digest di 160 bit ed è basato su principi simili a quelli di MD5. Come per MD5, anche questo algoritmo è ormai ritenuto insicuro, ma rimane tuttavia tra i più diffusi algoritmi di hashing.
SHA-2: successore di SHA-1, SHA-2 non è il nome di un algoritmo di hashing, ma di un’intera famiglia di algoritmi. Sono stati infatti distribuiti quattro algoritmi di hashing, che producono digest man mano più lunghi. Di questa famiglia fa parte SHA-256, utilizzato nell’esempio sopra, che produce un digest di appunto 256 bit.
SHA-3: è l’ultimo algoritmo della famiglia SHA, vincitore di una competizione che avrebbe eletto il nuovo standard NIST.
Bcrypt: a differenza degli algoritmi citati finora, bcrypt è stato studiato appositamente per l’hashing delle password. Incorpora un passo di salting al suo interno ed è l’algoritmo predefinito su sistemi BSD e SUSE Linux.
Sebbene esistano moltissimi algoritmi di hashing, alcuni anche molto diffusi, occorre sempre considerare la robustezza dell’algoritmo, optando per l’utilizzo di algoritmi sicuri e comprovati, sopratutto nella protezione di password e dati sensibili.
Conclusioni
Le funzioni di hashing rappresentano uno strumento importante nella sicurezza informatica, utili per la verifica di messaggi e comunicazioni, fondamentali per la protezione di password e dati sensibili.
L’utilizzo di questo tipo di tecniche è ormai intrinseco in tutti i tipi di tecnologie, dai sistemi operativi ai password manager, fino alle blockchain. Per questo motivo è importante conoscerle e saper distinguere tra un algoritmo di hashing sicuro e uno desueto per salvaguardare i propri dati.