La sicurezza delle informazioni prevede vari requisiti: confidenzialità, integrità e disponibilità (detti requisiti CIA), che, a seconda dei casi, possono essere necessari oppure no. Tra tutti, il requisito dell’integrità è ampiamente sottovalutato: perché?
Firma digitale, la guida tecnica completa: tutti gli aspetti matematici le applicazioni
Definizione di integrità delle informazioni
Il requisito dell’integrità richiede che le informazioni a noi giunte (dalla rete, dal disco, da una penna USB) siano fedeli a quelle originali, e dunque non alterate, per errore di trasmissione o per volontà di un avversario.
Ciò premesso, appare abbastanza ovvio che tutti noi, nell’uso di un qualunque dispositivo, ci aspettiamo che le informazioni visualizzate siano originali e prive di contraffazione. In altre parole, potremmo dire che desideriamo sempre che le informazioni siano integre. Ciò significa dunque che il requisito dell’integrità è sempre desiderato.
Sottovalutazione del requisito di integrità
Da quanto osservato segue l’attributo di sottovalutazione: se il requisito è sempre voluto (chi vorrebbe consultare informazioni manomesse?), dovrebbe essere sempre esplicitato nei domini applicativi, ma ciò di fatto accade solo occasionalmente.
Molti operatori si affrettano a richiedere altri requisiti (ad esempio, la cifratura) ma non si soffermano sull’integrità, quasi lo considerassero ovvio. Eppure, in fase progettuale, dovrebbe essere sempre esplicitato (non dimentichiamo il celebre approccio vincente security-by-design). Per fortuna in alcune applicazioni che fanno uso della rete i (noti) protocolli TLS e IPsec,[1] talvolta usati per altre ragioni, garantiscono l’integrità.
La garanzia di integrità: come funziona l’impronta
Nel modello di riferimento, denominiamo Alice la sorgente delle informazioni e Bob il destinatario: immaginiamo che Alice mandi un file a Bob, che ne richiede l’integrità. Alice e Bob non sono necessariamente persone ma possono essere dispositivi di memorizzazione (cloud incluso) o anche programmi in esecuzione (detti processi).
Se Bob ha richiesto l’integrità allora Alice, nel mandare a Bob un file F, invierà anche un altro file T (chiamato in molti modi, ma qui denominato impronta,[2] esistente ai fini dell’integrità) unicamente dipendente da F. Dunque, Alice invia la coppia (F, T). Bob riceve una coppia (F’, T’) che auspicabilmente coincide con la coppia inviata da Alice, ma, appunto, si pone un dubbio relativo all’integrità: F’ è veramente coincidente con F?
Teniamo presente che l’impronta è studiata in maniera tale da variare rispetto all’originale se il file riceve una modifica, con la caratteristica che l’impronta è molto più concisa e maneggevole del file che la origina.[3]
L’approccio prevede che Bob abbia a disposizione un algoritmo di verifica che, dato F’, permette di calcolarne l’impronta T” e la confronti con T’. Se il confronto ha esito positivo (le due impronte cioè coincidono) il file F’ (quello ricevuto) è considerato integro e dunque eguale ad F (file originale); se fallisce, allora si è verificato un problema che ha cambiato il file F, ma nulla si può dire sulla sua natura (frode o errore trasmissivo). In caso di fallimento, non è dato conoscere il contenuto del file originale.
Quindi la garanzia di integrità consiste nella possibilità di verificare se il file ricevuto è integro o no e non consiste (come molti credono) nella certezza di ricevere un file integro.
L’importanza dei canali differenti
Si noti che la validità di questo approccio si basa sul fatto che file ed impronta vengano inviati su due canali diversi, rendendo meno plausibile l’attacco (detto del man-in-the-middle, o MITM) dove l’avversario, che controlla il canale trasmissivo, sostituisce F con G e T con l’impronta di G, superando perciò la verifica fatta da Bob.
L’uso di canali di comunicazione diversi riduce la probabilità che siano entrambi controllati dall’avversario, ma non la elimina. Il metodo, perciò, non sembra perfetto e lascia con un interrogativo di fondo: si può fare di meglio? La risposta è sì, ma per poterne parlare abbiamo bisogno di più dettagli, che vedremo nel seguito.
Intanto osserviamo che in molti siti web, che consentono il download di software, si pubblica anche l’impronta dello stesso, consentendo di fare la verifica (non vogliamo installare qualcosa che non sia l’originale).
Software e impronta dovrebbero rispettare il requisito dei canali differenti e la cosa in pratica si traduce nel fatto che i due file risiedono su server web differenti. L’uso del protocollo https, che impiega TLS, o di http/3 (che impiega QUIC), garantisce implicitamente l’integrità per cui, in tali situazioni, Alice invierà solo il file, mentre l’impronta sarà automaticamente aggiunta e verificata dai protocolli.
Cosa è l’autenticità con un esempio
La definizione di integrità già fornita lascia a desiderare. Per capirlo useremo un esempio, in cui si fa riferimento a un sito web che consente il download di un file. Si supponga di mettere in atto tutte le metodiche già descritte per garantire l’integrità. Eppure, l’avversario potrebbe direttamente attaccare il sito (o siti) web, sostituendo i file ivi contenuti con altri file scelti appositamente. In tal caso i file inviati dal sito web saranno integri, ma saranno prodotto della manomissione introdotta dall’attaccante.
In effetti potremmo dire che viene meno un requisito di originalità del file che finisce con il determinare la mancanza di integrità in una situazione complessa, dove l’integrità viene garantita non globalmente, ma solo in relazione all’ultimo segmento di comunicazione. Introducendo una nuova terminologia diremo che è venuta meno l’autenticità del file. In tal caso la sua integrità è inutile perché garantisce i contenuti stabiliti dall’avversario.
L’autenticità è dunque un rafforzamento dell’integrità che abbraccia l’intero ciclo di vita del file. Bob ha a disposizione un metodo che gli permette non solo di verificare l’impronta, ma anche di verificare l’identità di Alice. Sia chiaro, tale verifica di identità consiste solo in un riconoscimento del soggetto come quello atteso e non implica necessariamente l’identificazione (in caso di persona).
In altri termini, Bob può essere sicuro che il file è stato inviato integro proprio dal soggetto che Bob ritiene dover essere il mittente.
Ricorrere alla firma digitale apposta da Alice sul file è più di quanto necessario, perché permette di conoscere l’identità di Alice. Inoltre, si configura come economicamente oneroso, perché i provider del servizio di firma digitale sono a pagamento, e computazionalmente gravoso, perché calcolo e verifica della firma richiedono uno sforzo computazionale ben più significativo del necessario. Non da ultimo, richiede la presenza di una infrastruttura apposita, la PKI.
Nella prossima sezione vedremo come ottenere gratuitamente e semplicemente la garanzia di autenticità.
Le funzioni hash: strumenti per integrità ed autenticità
Intanto premettiamo che la garanzia di integrità o autenticità consiste nel poter usare un algoritmo di verifica che risponde positivamente o negativamente. Nel caso negativo non è possibile determinare il contenuto originale.
Sorvolando su vari approcci che sono stati tentati in passato, vogliamo sottolineare che oggi il principale approccio si basa sul calcolo dell’impronta di un file mediante una funzione hash, che può essere di due tipi: unkeyed (senza chiave) o keyed (con chiave).
Le funzioni hash nascono unkeyed e poi, tramite alcune tecniche, sono state rese keyed. Ma procediamo per passi.
Di funzioni hash abbiamo parlato nell’articolo Firma digitale, la guida tecnica completa: tutti gli aspetti matematici le applicazioni; precisiamo che si trattava di funzioni unkeyed.
Essenzialmente, una funzione hash (unkeyed) può essere immaginata come una scatola che prende in input un file qualsiasi e produce in output, in maniera deterministica, una sequenza di bit di lunghezza prefissata, che appare del tutto casuale e che dipende unicamente dall’input. Ogni modifica dell’input produce una modica dell’output.
Poiché le funzioni hash sono usate in informatica anche per altri scopi completamente differenti, richiediamo che esse abbiano qualità crittografica. Prima di elencarne le proprietà definiamo collisione il fenomeno per cui due file differenti hanno la stessa impronta. Sebbene le collisioni siano sgradite, esse sono inevitabili e derivano da semplici proprietà matematiche, che evitiamo qui di discutere, ma legate al fatto che le impronte hanno lunghezza fissa e breve.[4] In pratica tutte le funzioni hash hanno (molte) collisioni: l’importante è che sia difficile trovarle.
Funzioni hash e qualità crittografica
Proprietà che rendono una funzione hash di qualità crittografica:
- La lunghezza dell’impronta calcolata non sia troppo piccola, ove, attualmente, ciò significa che deve superare 160 bit[5];
- data l’impronta, non è possibile determinare il file originale[6];
- non è possibile determinare due file differenti che abbiano la stessa impronta.[7]
È interessante sapere che esistono varie funzioni hash che si pensa siano di qualità crittografica, ma dimostrare matematicamente la loro esistenza è un problema aperto ed importante. Si noti inoltre che la proprietà n. 2 può essere violata con metodi basati sulle cosiddette rainbow table che consistono essenzialmente in tavole di impronte pre-calcolate e consultabili: ciò non distrugge la qualità crittografica. Le rainbow table sono molte usate per l’individuazione di password.[8]
Esistono varie liste di funzioni ritenute di qualità crittografica,[9] mentre esistono altre funzioni che lo erano in passato, ma poi sono state compromesse. Fra queste ultime sono da notare i casi di MD5, ancora usata da molti “esperti” in ambito forense, ma compromessa (e quindi inutile) da anni, e SHA-1, dichiarata obsoleta da Google nel 2014.
Fra le più popolari funzioni hash di (probabile) qualità crittografica annoveriamo le famiglie SHA-2 e SHA-3. Nella Fig. 1 sono illustrati i valori SHA-256 (membro della famiglia SHA-2) scritti in esadecimale (che riduce a un quarto la dimensione della stringa binaria) delle parole “piffero”, “p1ffero”, “p1ffer0”, “c@s@” e “casa”. Si può notare come le impronte appaiano profondamente differenti.
Figura . Uso del comando echo -n <stringa> in pipeline al calcolo di SHA-256. Il comando echo -n <stringa> produce <stringa> in output (senza newline) e la pipeline serve a fornire l’output di echo come input a shasum -a256, che esegue lo SHA-256. Il trattino orizzontale nell’output indica che l’input non è stato fornito attraverso un file ma come standard input (nel senso usato dai programmatori C).
Dunque, in base a quanto discusso, garantiamo l’integrità nel senso già specificato calcolando le impronte dei file tramite funzioni hash (unkeyed) di qualità crittografica. Per garantire l’autenticità (che implica l’integrità) rendiamo le funzioni hash keyed.
In pratica, per il calcolo dell’impronta, non usiamo più solo il file originale, ma anche una chiave segreta, condivisa fra Alice e Bob. Una chiave è una sequenza di bit apparentemente casuale e di lunghezza prefissata (che può essere ad esempio il valore di una funzione hash[10]). Ovviamente una chiave è diversa da una password (anche se simile), ammettendo variabilità maggiore; a differenza di una chiave, una password è infatti “condannata” ad essere digitabile da tastiera. Detta k la chiave, e data una funzione hash unkeyed h (di qualità crittografica), possiamo ottenere una funzione keyed in molti modi, ad esempio calcolando lo hash h(k‖<file>‖k), dove il simbolo ‖ rappresenta la concatenazione.[11]
Un altro celebre modo è ricorrere al cosiddetto HMAC. Ovviamente la verifica lato Bob avverrà calcolando l’impronta a partire dal file ricevuto e dalla chiave condivisa. Una funzione keyed garantirà l’autenticità perché l’avversario non conosce la chiave e, anche se fosse in grado di produrre una collisione, non potrebbe verificarne la correttezza in quanto non conosce la chiave. La verifica positiva effettuata da Bob implica che solo chi conosceva la chiave segreta (appunto Alice) poteva aver calcolato l’impronta ricevuta.
L’autenticità sul web
Il metodo descritto per verificare l’autenticità, sebbene valido, non è direttamente applicabile al caso del web, poiché non si può pensare a una chiave segreta condivisa fra il server web e il pubblico. Esistono vari modi di stabile una chiave comune e segreta fra due soggetti che non hanno mai comunicato (questo problema prende il nome di key exchange) e quindi raggiungere la sicurezza del keyed hashing.
Esistono anche altre tecniche più complesse che derivano l’impronta non da un keyed hash ma da una cifratura autenticata, che qui non approfondiremo.
Ribadiamo che l’uso dei già citati protocolli crittografici TLS e/o IPsec fornisce l’autenticità, poiché il calcolo dell’impronta, con il key exchange e una successiva verifica, avviene automaticamente.
È semplice dedurre che l’uso del semplice protocollo http (versioni 1 e 2) non dà garanzia alcuna di integrità, permettendo attacchi MITM alla portata di tutti: amici, colleghi, intrusi e attaccanti appositamente organizzati. Ne segue che una organizzazione che fornisse servizi intranet tramite http sarebbe facilmente vittima di violazioni (e lo scrivente ne ha assistito alcune importanti).
___________________________________________________________________________________
Note
- Spesso usato per le VPN. ↑
- Celebri sinonimi di impronta sono message digest, o semplicemente digest, fingerprint, message authentication code (abbreviato con MAC e da non confondere con gli indirizzi di livello due in una rete) e message authentication tag. ↑
- Assistiamo frequentemente ad impronte lunghe 256 o 512 bit, anche se esistono altre lunghezze. La dimensione dell’impronta è fissa ed indipendente dalla dimensione del file che la origina. ↑
- Per un utile approfondimento si può vedere il cosiddetto paradosso del compleanno (https://en.wikipedia.org/wiki/Birthday_problem) e l’attacco che lo sfrutta (https://en.wikipedia.org/wiki/Birthday_attack). ↑
- Il numero 160 deriva dalle proprietà matematiche stabilite dal paradosso del compleanno, citato nella nota 4. ↑
- Per essere più precisi, non si dovrebbe parlare di impossibilità assoluta, ma di impossibilità in tempi “umani”. Ciò permette di considerare inutili gli approcci ove il calcolo del file originale avviene in millenni, tramite forza bruta (https://en.wikipedia.org/wiki/Brute-force_attack). ↑
- Impossibile nel senso precisato nella nota 16. ↑
- Spesso le password sono memorizzate, lato server, calcolandone l’impronta ed evitando di registrare la password in chiaro; per risalire alla password originale si può far uso di una rainbow table come quella in https://crackstation.net/. ↑
- Nella lista sono incluse funzioni che sono state di qualità crittografica ma che oggi non lo sono più. ↑
- Esistono le key derivation function (KDF), che sono essenzialmente delle funzioni hash di qualità crittografica che prendono in input una password e producono in maniera deterministica una chiave. Il vantaggio è l’avere i bit uniformemente distribuiti, cosa che è falsa nelle password, che debbono essere inseribili da tastiera, e il non dover ricordare la chiave ma solo la password, che è maggiormente sicura se non è una parola che si può indovinare o trovare in un dizionario e anche più semplice da imparare a memoria.↑
- Le scelte h(k‖<file>) e h(<file>‖k) sono insicure. ↑