L’archiviazione sicura delle password è un tema sempre più al centro delle preoccupazioni di tutti noi. Affrontiamo questo argomento attraverso il contributo dell’esperto Pierluigi Paganini.
di Pierluigi Paganini*
I numerosi incidenti informatici degli ultimi anni hanno portato all’attenzione dei media il problema della sicurezza nella gestione delle password.
A seguito di molti attacchi informatici gli utenti di servizi web si sono visti pubblicare le proprie credenziali in rete o le stesse sono state oggetto di commercializzazione nell’ecosistema criminale.
Va detto subito che in taluni casi queste informazioni erano archiviate in chiaro nei sistemi presi di mira dagli hacker. Tuttavia, a volte vi sarà capitato di leggere che gli hacker avevano avuto accesso solo all’hash delle password archiviate nei sistemi compromessi.
Quando parliamo di password, quindi, cerchiamo di comprendere meglio cosa significano concetti come hash, salt e funzione di derivazione.
L’hash delle password
È buona norma non archiviare le password degli utenti in chiaro in un database. I principali servizi web archiviano nei loro sistemi le impronte delle password, i cosiddetti hash.
Una funzione hash è una funzione che, a fronte di una stringa arbitraria di ingresso, fornisce in uscita una stringa di lunghezza fissa la cui dimensione è funzione dell’algoritmo utilizzato.
Una funzione di hash non è invertibile, ciò significa che non esiste una funzione che a partire dall’hash è in grado di restituire la stringa originaria.
Le principali funzioni di hash sono MD5, RIPEMD, SHA. Se avete voglia di fare qualche prova, ci sono siti web che lo calcolano on line, come il sito riportato a questo link.
Ritornando alle password, inizialmente nel database era possibile trovare i valori di hash, tipicamente calcolati con gli algoritmi MD5 e SHA-1, prima che si scoprisse che tali funzioni in realtà non erano sicure. Per questo motivo tali funzioni sono state soppiantate dall’algoritmo SHA-256.
Attacchi di Dizionario e di Bruteforce
Ipotizzando di essere riusciti ad accedere a un database, trovandoci dinanzi una lunga lista di credenziali utente composte da username e hash delle password, come possiamo ricavarci la password, essendo le funzioni di hash non invertibili?
In linea teorica dovremmo cercare di pensare a una possibile password, calcolarne l’hash e verificare se all’interno del DB è presente tale hash. In caso affermativo avremmo trovato la password dell’utente.
Dovendo ripetere l’operazione per tutti gli utenti nell’archivio, dovremmo necessariamente usare una delle metodiche che andremo a breve a descrivere, ovvero attacchi di dizionario e di bruteforce.
Per gli attacchi ti tipo dizionario l’attaccante si prepara un file contenente le password e le frasi di uso più comune. Provvederà quindi a calcolare l’hash di ciascuna di essa, per ottenere quindi un file di hash relativi a password note. A questo punto si cercheranno nell’archivio trafugato gli hash corrispondenti a quelli calcolati dal dizionario.
Per ogni corrispondenza avremmo trovato la password del relativo utente, essendo noi a conoscenza della password presente nel dizionario di partenza e usato per il calcolo del file di hash.
Esempio
Immaginiamo che nel DB siano presenti le seguenti credenziali:
Username | PWD (SHA 256) |
admin | 7146084e6f06271dc0c85182476244f2b2d4f0f8fcc9e0dc9c250b83cce9ceb0 |
Felice Russo | ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f |
Marco Indomabile | 008be6875298f5a65763851b274e87055f3101a9c0477e583813c187cba187e6 |
E immaginiamo che il nostro dizionario sia per semplicità composto da 3 password: admin, 12345678, 1234.
Calcoliamo l’hash per ciascuna voce del dizionario.
Password | PWD (SHA 256) |
admin | 8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918 |
12345678 | ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f |
pippo | a2242ead55c94c3deb7cf2340bfef9d5bcaca22dfe66e646745ee4371c633fc8 |
Notate nulla di strano?
L’hash della password dell’utente Felice Russo è il medesimo di quello calcolato per la stringa ‘12345678’, che quindi risulta essere la password che cercavamo.
Tanto più ampio sarà il dizionario, più alta sarà la possibilità di scovare la password dell’utente. È chiaro che una idonea politica di scelta delle password potrebbe complicare il lavoro all’attaccante.
Passiamo all’attacco di tipo brute force, in cui sono provate tutte le possibili combinazioni di caratteri per la composizione di stringhe di una data lunghezza.
Dal punto di vista computazionale questo attacco è molto impegnativo, sebbene converga sempre alla password ricercata in quanto sono provate effettivamente tutte le combinazioni possibili.
Password lunghe richiederanno maggior tempo per essere indovinate.
Cosa sono le Lookup Tables?
Le lookup tables sono tabelle che consentono di hackerare diversi hash allo stesso tempo e molto velocemente. Viene creato un dizionario di hash che è utilizzato per cercare gli stessi hash nel DB e, in caso di corrispondenza, recuperare la password a essa associata. Il vantaggio consiste nella possibilità di calcolare centinaia di hash per secondo grazie a queste strutture.
In Rete esistono servizi come CrackStation’s free hash cracker, che calcolano gli hash ricercandoli in tabelle precompilate. Guardate cosa accade se fornisco in input l’hash che avevamo recuperato nell’esempio precedente:
ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f
Esattamente la medesima password scoperta in precedenza, ovvero ‘12345678’.
Abbiamo imparato perché è importante non memorizzare in chiaro le password in un database e perché le procedure di hashing da sole non bastano per metterci al sicuro dagli hacker.
Il salting degli hash delle password
Introduciamo la tecnica nota come salting degli hash delle password, che consente di annullare l’efficacia dei metodi di attacco illustrati finora.
Prima facciamo un passo indietro. Qualche anno fa, non appena scoperta la possibilità di hackerare facilmente gli algoritmi di hashing MD5 e SHA1, gli esperti di sicurezza hanno optato per l’adozione dei “salt” per aumentare la complessità e la sicurezza della password e rendere vani gli attacchi descritti.
Il “salt” non è altro che una stringa che viene apposta in testa o in coda alla password, prima che ne venga calcolato l’hash.
La procedura quindi aumenta la difficoltà nell’individuazione della password a partire dall’hash.
Il principale errore nell’implementazione della tecnica di “salting” è l’aggiunta di una stringa di “salt” unica per tutte le password.
Perché il salting dell’hash è sbagliato per la sicurezza delle password?
Partiamo dall’assunto che la maggior parte degli utenti utilizza password semplici e che spesso usa sempre la stessa password per autenticarsi (le password più usate sono sempre “admin”, “password”, “12345678”, “87654321”). Un attaccante che ha accesso al database in cui sono presenti gli hash delle password degli utenti potrebbe trovarsi un certo numero di hash uguali, corrispondenti a password semplici usate dagli stessi utenti e a cui è stato apposto sempre il medesimo salt.
A questo punto, applicando metodi di aggregazione diventa un gioco da ragazzi riuscire a scoprire la password originaria e il relativo salt usato.
Tuttavia, essendo il salt uguale per tutte le password, l’intero processo di salting verrebbe vanificato. Addirittura, più corta è la stringa di salting più semplice sarà individuare la password, questa volta mediante un attacco di brute force.
Funzione di derivazione della password
Chiaramente si potrebbe ovviare utilizzando salt diversi per ciascuna password. In questo modo ci metteremmo al riparo da attacchi di tipo statistico, come quello descritto nel caso di salt costanti.
I salt “dinamici” devono essere generati in maniera pseudocasuale. Per far ciò necessitiamo di una funzione che compia per noi l’operazione, la cosiddetta funzione di derivazione della password (anche nota come Key Derivation Function).
Una funzione di derivazione riceve in input una chiave, una stringa di “salt” e un numero di iterazioni che corrisponde al numero di volte che viene ripetuto il processo di hashing.
La funzione di derivazione più popolare è PBKDF2 (Password-Based Key Derivation Function) che fa parte dell’implementazione dello standard RSA Laboratories’ Public-Key Crittografy Standards (PKCS).
La funzione PBDKF2 è una funzione di derivazione che applica una funzione pseudo casuale. I valori di input del PBDKF2 sono i seguenti:
- P password;
- S salt;
- C Count Iterator
- DKLEN (lunghezza chiave derivata)
Altra soluzione è Bcrypt, che non usa una funzione di hash per l’elaborazione bensì una funzione di cifratura a blocchi. Il vantaggio è principalmente legato alla velocità di esecuzione della funzione e al suo ridotto consumo di risorse rispetto alla PBDKF2.
L’utilizzo di stringhe di salt casuali rende quindi efficaci i processi di salting a protezione delle password degli utenti.
I metodi appena descritti confermano, se ancora ce ne fosse bisogno, che la protezione delle password è un tema caldo, che coinvolge ognuno di noi.
Il salting degli hash e le funzioni di derivazione, unite al buon senso nello scegliere e custodire le password, possono sicuramente aumentare la sicurezza della nostra identità digitale.
*Pierluigi Paganini
Membro Gruppo di Lavoro Cyber G7 2017 presso Ministero degli Esteri
Membro Gruppo Threat Landscape Stakeholder Group ENISA
Collaboratore SIPAF presso il Mef