Annoso problema. Ho delle informazioni sensibili, magari delle chiavi di
cifratura o delle password applicative e non so dove memorizzarle.
Java, ci mette a disposizione un luogo molto interessante, dove riporre al
sicuro i nostri secret: il
KeyStore.
Il KeyStore è un file binario, cifrato in maniera simmetrica, solitamente
utilizzato per memorizzare i certificati.
Dalla documentazione
Oracle,
abbiamo una definizione più ampia dello scopo con cui è stato progettato il
KeyStore:
A database called a “keystore” can be used to manage a repository of keys and
certificates. Keystores are available to applications that need data for
authentication, encryption, or signing purposes.
Ogni applicazione, implementando la classe KeyStore, nel package java.security,
può scegliere 3 diversi formati per il file:
jks: il formato di default, cifrato con un algoritmo custom dato da Oracle
jceks: sempre un formato binario, ma con una cifratura più forte, basata su triple des
Il nostro keystore, non è altro che un file binario, cifrato con una chiave
attraverso un 3DES. Essendo questa, crittografia simmetrica, la stessa chiave
usata per cifrare dovrà essere usata per decifrare il file.
Spostiamo quindi un po’ il problema. Usiamo un keystore per memorizzare dei
segreti, ma abbiamo bisogno di un segreto per sbloccare il keystore. Già,
bizzarro. Non storcete però il naso. La chiave del keystore, che a questo punto
è quello che dovete proteggere, può essere:
passata a runtime in una variabile d’ambiente o a riga di comando
cablata nel codice, magari offuscato
letta a runtime all’interno delle operazioni di avvio della vostra
applicazione
Ogni approccio ha i suoi pro e i suoi contro. Io credo sinceramente che
l’approccio della chiave nel codice, offuscato sia quello più versatile. Ci
sono molti tool per
rendere il bytecode java difficilmente comprensibile. Attenzione, nessuno
di essi offre il 100% di sicurezza contro il reverse.
Leggo e scrivo dal Keystore
Per salvare un valore nel keystore, utilizzo la classe
javax.crypto.PBEKeySpec,
che offusca il valore garantendo un livello di protezione adeguato per una
password. Ricordiamoci che comunque il keystore è cifrato con triple des.
Il metodo getKey, recupera la chiave specificata come parametro, dal keystore
con una particolare password.
Ecco il nostro main che mostra come usare le routine per memorizzare una chiave
nel nostro keystore. A questo punto diventa critica la password con cui
cifriamo il keystore. Non usate test123 mi raccomando!
Questo è il contenuto del nostro keystore. L’unica cosa in chiaro, a parte la
chiave “test” è il tipo dell’oggetto memorizzato, java/lang/String.
Sinceramente, accettabile come perdita di confidenzialità.
Off by one
Il KeyStore può essere usato per memorizzare delle coppie chiave valore, come
parametri o credenziali. Il tutto deve essere protetto da una password per la
cifratura simmetica dell’archivio utilizzato.
A questo punto, come dicevamo nell’introduzione, non resta che scegliere la
strategia migliore per proteggere quest’unica parola chiave. Per quanto ho
avuto modo di vedere, il KeyStore è un po’ sottovalutato come store sicuro per
riporre le credenziali. Perché non integrarlo in Android ed evitare password
memorizzate in file di configurazione?
Disclaimer
Il codice è stato preso ed adattato da questo post su
StackOverflow.
Avevo in mente di cambiare l’algoritmo per l’offuscamento del secret nel
KeyStore, usando AES invece del Password Based
Encryption.
Poi ho preferito lasciar stare, non tanto per pigrizia, visto che per i fatti
miei avevo già le chiamate pronte, ma perché sinceramente non mi dispiace usare
quest’API.
Ho aggiunto il codice per creare il file del KeyStore.
A questo punto, l’evoluzione è memorizzare tutto in una classe ed incorporarla
nei vostri progetti.