PDA

View Full Version : [Java + MySQL] Errore nella memorizzazione di una password criptata con MD5


luxorl
11-06-2008, 10:35
Ho un piccolo problema.
In pratica quando il sistema aggiunge un nuovo utente prima di inserire la password nel DB MySql la cripta con MD5.


private String cryptPassword(final String password) {
MessageDigest md=null;
try {
//we use MD5 Algorithm
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
md.update(password.getBytes());
return new String(md.digest());
}


Quando un utente fa il login il sistema prende la password inserita dall'utente la cripta e la confronta con quella già criptata conservata nel DB.

Sembrava andare tutto ok, fin quando per caso non ho usato la password: "direttore".

In pratica usando nel prompt-msdos l'algoritmo MD5 con input "direttore" mi restituisce questa cosa

àLa☺ ×fá`¾e¦☼â♫&


Mente nel DB se accedo tramite MySql Administrator trovo solo questo:
http://img165.imageshack.us/img165/2245/errorehc8.jpg

Non succede con le altre password provate fin'ora.
Come mai? E' lo spazio che crea problemi? Sono quei caratteri speciali? Uso male l'algoritmo MD5? come risolvo?

Aiutatemi per favore :ave:

NB: nel DB la password viene memorizzata come VARCHAR

banryu79
11-06-2008, 11:05
Ciao,

premetto che non me ne intendo per nulla, nel senso che non so come funziona l'agoritmo MD5 percui potrei suggerirti un'amena cazzata.

Però leggendo qua:

...
md.update(password.getBytes());
...

si nota che ti stai facendo restituire la codifica della tua String con il metodo getBytes() che usa il charset di default della piattaforma e se la stringa, per qualche ragione, non è codificabile con quel charset [non esiste una mappatura per il dato carattere, cosa che non credo sia nel tuo caso, oppure la stringa è "malformata"] il comportamento è indefinito.

Prova ad usare il metodo .getBytes(Charset charset) : specificando un Charset esplicitamente in caso di problemi con la stringa la sequenza di caratteri malformata viene rimpiazzata con un array di byte di default per il dato Charset (Vedi le API Javadoc a riguardo)

In ogni caso credo che sarebbe meglio usare la versione che prende il Charset esplicitamente definito dal programmatore, perchè il Charset di default (quello utilizzato dal sistema, ci pensa la Jvm a pescarlo) può essere diverso tra diversi sistemi operativi.

luxorl
11-06-2008, 11:16
Ciao,

premetto che non me ne intendo per nulla, nel senso che non so come funziona l'agoritmo MD5 percui potrei suggerirti un'amena cazzata.

Però leggendo qua:

...
md.update(password.getBytes());
...

si nota che ti stai facendo restituire la codifica della tua String con il metodo getBytes() che usa il charset di default della piattaforma e se la stringa, per qualche ragione, non è codificabile con quel charset [non esiste una mappatura per il dato carattere, cosa che non credo sia nel tuo caso, oppure la stringa è "malformata"] il comportamento è indefinito.

Prova ad usare il metodo .getBytes(Charset charset) : specificando un Charset esplicitamente in caso di problemi con la stringa la sequenza di caratteri malformata viene rimpiazzata con un array di byte di default per il dato Charset (Vedi le API Javadoc a riguardo)

In ogni caso credo che sarebbe meglio usare la versione che prende il Charset esplicitamente definito dal programmatore, perchè il Charset di default (quello utilizzato dal sistema, ci pensa la Jvm a pescarlo) può essere diverso tra diversi sistemi operativi.

E se evitassi di usare stringhe?
Nel senso posso farmi restituire e quindi memorizzare direttamente byte[]?


private byte[] cryptPassword(final String password) {
MessageDigest md=null;
try {
//we use MD5 Algorithm
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
md.update(password.getBytes());
return md.digest();
}


Ecco alcuni risultati di criptaggio di varie password:


[B@19821f
[B@addbf1
[B@42e816
[B@9304b1
[B@190d11
[B@a90653
[B@de6ced
Premere un tasto per continuare . . .


Secondo voi così va bene?

^TiGeRShArK^
11-06-2008, 11:21
E se evitassi di usare stringhe?
Nel senso posso farmi restituire e quindi memorizzare direttamente byte[]?


private byte[] cryptPassword(final String password) {
MessageDigest md=null;
try {
//we use MD5 Algorithm
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
md.update(password.getBytes());
return md.digest();
}


Ecco alcuni risultati di criptaggio di varie password:



Secondo voi così va bene?
no, perchè applicando il toString al byte array ti viene restituito il reference dell'oggetto.
Ti conviene fare come suggerito da Banryu utilizzando una charset comune (direi che UTF-8 dovrebbe andar bene così ad occhio).

luxorl
11-06-2008, 11:22
Però così ho problemi a livello di Entity Bean.
Perché l'attributo password nell'EntityBean, essendo il campo password del DB MySql un VARCHAR, è una Stringa. :(

luxorl
11-06-2008, 11:23
no, perchè applicando il toString al byte array ti viene restituito il reference dell'oggetto.
Ti conviene fare come suggerito da Banryu utilizzando una charset comune (direi che UTF-8 dovrebbe andar bene così ad occhio).

Ok, testo subito

banryu79
11-06-2008, 11:30
Ti conviene fare come suggerito da Banryu utilizzando una charset comune (direi che UTF-8 dovrebbe andar bene così ad occhio).

Incredibile, non ho sparato una cazzata! :eek: [w i Javadoc:D]

shinya
11-06-2008, 11:33
Nota a margine: per l'amor di dio non usare MD5. E' rotto. L'algoritmo intendo.

Non va più bene per le password, usa bcrypt o sha-256 (o maggiore). Esistono implementazioni già fatte in java di entrambi gli algoritmi.

E se proprio devi usare MD5 (che è un colabrodo) almeno fai il salt delle password. Fare il 'salt' vuol dire aggiungere un pezzo arbitrario (tipo il nome dell'utente, o una stringa random che poi ti tieni sul db) alla password e criptare quello e non solo la password.

Esempio: invece di fare md5('direttore'), fai md5('utente.' + 'direttore'), oppure md5('$OMG!1PWNAGE!11' + 'direttore') dove la prima stringa è generata casualmente.

^TiGeRShArK^
11-06-2008, 11:35
Nota a margine: per l'amor di dio non usare MD5. E' rotto. L'algoritmo intendo.

Non va più bene per le password, usa bcrypt o sha-256 (o maggiore). Esistono implementazioni già fatte in java di entrambi gli algoritmi.

E se proprio devi usare MD5 (che è un colabrodo) almeno fai il salt delle password. Fare il 'salt' vuol dire aggiungere un pezzo arbitrario (tipo il nome dell'utente, o una stringa random che poi ti tieni sul db) alla password e criptare quello e non solo la password.

Esempio: invece di fare md5('direttore'), fai md5('utente.' + 'direttore'), oppure md5('$OMG!1PWNAGE!11' + 'direttore') dove la prima stringa è generata casualmente.
fico non lo sapevo :fagiano:
io se non ricordo male usavo MD5 + il salt, ma non credevo che MD5 fosse combinato così male :asd:

luxorl
11-06-2008, 11:44
Ok posso usare un altro algoritmo ma prima vorrei risolvere questo problemino :D

Niente!
Utilizzando UTF-8 ho lo stesso identico risultato, forse il charset di default è proprio UTF-8? :confused: ....comunque il metodo modificato è questo:


private String cryptPassword(final String password) throws UnsupportedEncodingException {
MessageDigest md=null;
try {
//we use MD5 Algorithm
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
md.update(password.getBytes("UTF-8"));
return new String(md.digest());
}


Giusto no?
Provo ad usare un altro charset? quale?

luxorl
11-06-2008, 11:59
Il problema sembra risolto usando UTF-16.
Forse gli 8bit di UTF-8 non erano abbastanza per quei caratteri speciali?
Posso stare sicuro secondo voi che adesso va bene con tutte le password?

banryu79
11-06-2008, 12:06
Posso stare sicuro secondo voi che adesso va bene con tutte le password?

E chi lo sa? (io no).
Però seguirei i consigli di shynia: abbandona MD5 e fai il "salt" della password.
In questo modo credo tu possa raggiungere una ragionevole sicurezza.

luxorl
11-06-2008, 12:28
E chi lo sa? (io no).
Però seguirei i consigli di shynia: abbandona MD5 e fai il "salt" della password.
In questo modo credo tu possa raggiungere una ragionevole sicurezza.

Si ok, uso SHA e faccio il salt :D
Speriamo che non mi rifà lo scherzetto del Charset, qualcuno può darmi maggiore sicurezza da questo punto di vista? :stordita:

shinya
11-06-2008, 12:47
fico non lo sapevo :fagiano:
io se non ricordo male usavo MD5 + il salt, ma non credevo che MD5 fosse combinato così male :asd:

C'era un paper di due ricercatori cinesi che facevano vedere (con un metodo che solo un crittografo può capire) come generare dei plaintext con lo stesso md5-sum.

Qui trovi qualche link: http://www.schneier.com/blog/archives/2005/06/more_md5_collis.html

Anche sha-1 credo non stia benissimo. Se mi ricordo bene, credo sia stato dimostrato che si possano produrre collisioni ogni 2^69 invece dei soliti 2^80... però non ti fidare, cerca qualche paper che avvalori questa cosa.

luxorl
11-06-2008, 12:55
C'era un paper di due ricercatori cinesi che facevano vedere (con un metodo che solo un crittografo può capire) come generare dei plaintext con lo stesso md5-sum.

Qui trovi qualche link: http://www.schneier.com/blog/archives/2005/06/more_md5_collis.html

Anche sha-1 credo non stia benissimo. Se mi ricordo bene, credo sia stato dimostrato che si possano produrre collisioni ogni 2^69 invece dei soliti 2^80... però non ti fidare, cerca qualche paper che avvalori questa cosa.

Vabè è un sistema che dovrà girare intranet nella rete locale del dipartimento di ingegneria informatica.
Non sarà accessibile dall'esterno della LAN e gli utenti registrati non supereranno la dozzina...
Credo che con SHA posso stare sicuro, no?

shinya
11-06-2008, 13:07
Vabè è un sistema che dovrà girare intranet nella rete locale del dipartimento di ingegneria informatica.
Non sarà accessibile dall'esterno della LAN e gli utenti registrati non supereranno la dozzina...
Credo che con SHA posso stare sicuro, no?

Beh se fai il salt, anche con md5 sei al sicuro se i requisiti dell'applicazione sono quelli. Basta aggiungere il salt, cosi da scoraggiare qualche studentello curioso che ha googlato 'rainbow tables' :)

Cmq se vuoi stare dalla parte dei bottoni, come si dice da me, dai un'occhiata a questa libreria http://www.softabar.com/home/content/view/46/68/

Ho dato un'occhiata veloce ai javadoc e nella classe ShaUtil c'è un metodo per convertire l'array di byte in esadecimale (sotto forma di stringa). Cosi stai a posto e usi ascii.

luxorl
11-06-2008, 13:25
Beh se fai il salt, anche con md5 sei al sicuro se i requisiti dell'applicazione sono quelli. Basta aggiungere il salt, cosi da scoraggiare qualche studentello curioso che ha googlato 'rainbow tables' :)

Cmq se vuoi stare dalla parte dei bottoni, come si dice da me, dai un'occhiata a questa libreria http://www.softabar.com/home/content/view/46/68/

Ho dato un'occhiata veloce ai javadoc e nella classe ShaUtil c'è un metodo per convertire l'array di byte in esadecimale (sotto forma di stringa). Cosi stai a posto e usi ascii.

Ti ringrazio. Ho visto il metodo nel javadoc...
Appena posso lo testo e vi faccio sapere.

luxorl
11-06-2008, 13:43
sul forum di html.it ho trovato questo

Originariamente inviato da andbin
Volendo formattare l'array di byte secondo il formato tipico di un MD5 e volendo usare le nuove funzionalità di Java 5:

public static String bytesToHexString (byte[] ar)
{
StringBuilder sb = new StringBuilder (ar.length*2);
for (byte b : ar)
sb.append (String.format ("%02X", b));
return sb.toString ();
}
Ma si possono studiare soluzioni ancora più performanti.

Dovrebbe essere la stessa soluzione che si ottiene usando quella libreria no?

Angus
11-06-2008, 14:24
Prova anche a documentarti sulla codifica Base64 ;)