Elementi di crittografia: Gli algoritmi di hashing
Non spaventarti, continua a leggere!
Ho esordito in questo modo in quanto vedere nello stesso titolo parole come crittografia e algoritmi di hashing potrebbe intimorire.
Quello che in realtà voglio fare, in questa serie di articoli dedicati alla crittografia, è spiegare in modo molto semplificato e comprensibile (non scriverò nessuna formula matematica, lo giuro) il funzionamento e l’applicazione delle principali tecniche crittografiche. Alla fine sarai almeno in grado di spiegare ai tuoi clienti perchè non devono aver paura ad utilizzare la carta di credito per fare acquisti online (a determinate condizioni).
Gli argomenti che tratteremo saranno i seguenti:
- Algoritmi di hashing.
- Crittografia simmetrica.
- Crittografia asimmetrica.
Iniziamo con l’argomento di questo primo articolo ovvero gli algoritmi di hashing.
Mettiamo le stringhe nel tritatutto
In inglese to hash significa tritare la carne – pasticciare, praticamente fare delle polpette. Gli algoritmi da hashing in effetti fanno proprio questo. Prendono una stringa di una qualsiasi lunghezza e producono una stringa di una lunghezza definita (che varia a dipendenza del tipo di algoritmo) dalla quale non é più possibile risalire alla stringa originale. Ma vediamo subito nella pratica cosa significa.
Per farlo prendiamo in considerazione un algoritmo molto utilizzato e conosciuto (anche se per molti é superato) ovvero MD5. I principi che vedremo sono comunque validi per tutti gli algoritmi di hashing.
MD5 produce una stringa di 128 bit (32 caratteri) a partire da una stringa di lunghezza arbitraria.
Se passiamo “ciao” per MD5 otterremo questo hash
6e6bc4e49dd477ebc98ef4046c067b5f
Se vuoi fare delle prove, PHP mette a disposizione la funzione md5() il cui utilizzo è molto semplice:
echo md5("ciao");
Proviamo ora a passare l’intero contenuto di questo articolo a MD5, il risultato che otterremo sarà il seguente:
fd2f23f583ab1ebf44952a744f65bd6e
Sempre una stringa di 32 caratteri.
Ed ora vediamo una cosa molto interessante: passiamo il contenuto di quello stesso articolo, ma eliminando la prima virgola dal testo.
Il risultato sarà questo:
cae3c5fd98e04344be0cd2ccecde0a44
Questo ci porta alla prima importante applicazione degli algoritmi di hashing. Un hash completamente diverso solo per aver apportato una impercettibile modifica in una stringa lunghissima.
Checksum: evitare sorprese
Ti sarà certamente capitato, al download di un file, di trovare una scritta del genere
md5 checksum: cae3c5fd98e04344be0cd2ccecde0a44
Ebbene, a cosa serve?
Semplice. Chi mette a disposizione il file da scaricare, indica anche l’hash prodotto dall’applicazione di MD5 su tale file.
Una volta scaricato il file, potrà essere nuovamente passato per MD5 e l’hash prodotto dovrà essere identico. Se non lo è le cause possono essere due:
- Durante il download è andata persa o corrotta una parte del file (è sufficiente anche un solo bit come abbiamo visto).
- Durante il download il file è stato intercettato e modificato (magari con l’aggiunta di codice maligno).
In ogni caso, l’applicazione di questa tecnica ci mette al riparo da inutili rischi verificando l’integrità del file che abbiamo scaricato.
Nel web si possono trovare molte applicazioni per calcolare l’hash MD5 di un file, ad esempio questa.
Conservare le password in modo corretto
Purtroppo mi capita spesso di vedere delle piccole applicazioni casalinghe (a volte anche professionali (!)) nelle quali le password degli utenti sono salvate nel database così come sono, in chiaro. Questa è una procedura sbagliata ed assolutamente da evitare. I motivi essenzialmente sono due.
- L’eventuale violazione del database comporterebbe automaticamente la violazione delle password di tutti i nostri utenti. In questo modo il malintenzionato potrebbe loggarsi all’applicazione spacciandosi per qualunque utente (anche l’amministratore, perchè no). Inoltre considera che la maggior parte delle persone utilizza la stessa password per accedere a tutto. Dunque si tratterebbe di un’importante violazione della privacy dei nostri utenti.
- Sempre per una ragione di privacy, non è corretto che chi ha accesso al database (anche legittimamente) possa vedere le password degli utenti.
Per questa ragione, è necessario salvare le password passandole per un algoritmo di hashing. Dunque, prima di salvare la password nel database, la passerò ad esempio per MD5.
Quando l’utente inserirà i suoi dati di accesso, passerò la password che ha inserito per MD5 e confronterò la stringa prodotta con quella contenuta nel database.
In questo modo, anche se dovessi conoscere quanto contenuto nel campo password del database, non mi servirebbe a nulla. Non potrei infatti risalire alla password originale e non potrei utilizzare quella stringa come password, visto che al momento del login verrà passata per MD5 dando luogo ad una stringa diversa.
Limiti e rimedi
All’inizio di questo articolo dicevamo che MD5 è considerato superato. Vi sono due principali motivi alla base di questa affermazione:
Password deboli
Sappiamo che gli utenti utilizzano spesso delle password inadeguate, troppo comuni e banali. E sappiamo anche che è facile trovare nel web dei grandissimi database contenenti le associazioni tra stringa ed hash MD5.
Dunque se la mia password è “pippo”, il suo hash sarà:
0c88028bf3aa6a6a143ed846f2be1ea4
Ora prova ad inserire questo hash in uno dei tanti database, ad esempio questo.
Visto? Troppo facile!
Un possibile rimedio a questa debolezza è rendere la password dell’utente molto più complessa, e non è necessario che lui lo sappia. Come?
Definiamo due costanti nel nostro file di configurazione:
define(“PRE_PASSWORD”, “#$[[a56?][*{00l45%!@wrv7”); define(“POST_PASSWORD”, “Nel mezzo del cammin di nostra vita mi ritrovai in una selva oscura, che la diritta via era smarrita. Ahi quanto a dir qual era è cosa dura”);
Ora, quando salveremo la password, non ci limiteremo a passarla per MD5, ma anche a modificarla. Dunque non utilizzeremo questa procedura:
$PasswordDaSalvare = md5($password);
Ma:
$PasswordDaSalvare = md5(PRE_PASSWORD . $password . POST_PASSWORD);
In questo modo la stringa “pippo” diventerà:
#$[[a56?][*{00l45%!@wrv7pippoNel mezzo del cammin di nostra vita mi ritrovai in una selva oscura, che la diritta via era smarrita. Ahi quanto a dir qual era è cosa dura.
Che passata per MD5 darà questo hash:
8b1cc7082c7706a4929c8fc26e92a09e
Voglio vedere se la si trova in qualche database…
Naturalmente anche al login, quando l’utente inserirà “pippo”, prima di confrontarla con la stringa salvata nel database, dovremo aggiungere PRE_PASSWORD e POST_PASSWORD e passare per MD5.
Resistenza alle collisioni
In crittografia si parla di collisione quando un algoritmo di hashing produce lo stesso hash a partire da due stringhe diverse.
Abbiamo visto che MD5 produce sempre una stringa di 128 bit. Dunque i possibili hash di MD5 sono 2128.
E’ un numero veramente astronomico, ma è comunque un numero finito. Le possibili stringhe in entrata sono invece infinite in quanto non c’è un limite alla lunghezza che possono avere.
Possiamo concludere che vi è un numero teoricamente infinito di collisioni.
E’ per questa ragione che si parla di resistenza alle collisioni; Ovvero constatato che, a meno di limitare la lunghezza delle stringhe in entrata, le collisioni ci saranno, deve essere perlomeno impossibile individuarle. Dunque un algoritmo di hashing, per essere robusto, deve essere resistente alle collisioni.
Non deve essere quindi possibile individuare una procedura (o se individuabile deve essere computazionalmente improponibile) che possa mettere in relazione due stringhe che producono lo stesso hash.
In pratica se “pippo” da luogo a 0c88028bf3aa6a6a143ed846f2be1ea4, è possibile stabilire una procedura grazie alla quale posso individuare un’altra stringa che mi produca lo stesso hash?
Teoricamente sì. Conosciamo l’algortimo MD5 e possiamo studiare le peculiarità della stringa “pippo” che hanno portato a quell’hash.
Ma se la procedura che abbiamo individuato necessita dell’utilizzo di dieci super calcolatori per tre anni, allora questa procedura è computazionalmente improponibile e quindi praticamente inutile.
Per molti, sulla resistenza alle collisioni, MD5 sta iniziando a mostrare la corda e il consiglio è di utilizzare algoritmi della famiglia SHA.
Conclusione
In questo articolo abbiamo iniziato a calarci nell’affascinante mondo della crittografia. Spero di avere trattato l’argomento in modo sufficientemente semplice visto che il tema è parecchio ostico. Nel prossimo articolo vedremo i principi della crittografia simmetrica ovvero, per farla breve, come scambiarsi messaggi segreti.
E tu, utilizzi gli algoritmi di hashing per conservare le password? Che algoritmo ritieni più sicuro? Abitualmente verifichi l’hash dei file che scarichi (quando è disponibile)?
10 commenti
Trackback e pingback
[...] This post was mentioned on Twitter by Claudia ♀ | ./lsd ♫, Antonino Scarfì, nando pappalardo, mtx_maurizio, Your Inspiration…
[...] 04) Elementi di crittografia: Gli algoritmi di hashing [...]