Quanto è sicuro hashCode () di Java?

20

Sulle nostre viste in un'applicazione web Java, attualmente sto usando hashCode come Id per gli oggetti in modo che sul lato server posso recuperare lo stesso oggetto.

Tuttavia, mi chiedo quanto sia sicuro il hashCode di Java in realtà, in modo che qualcuno non possa hackerarlo per recuperare gli oggetti di altre persone. Non sono molto incline al meccanismo di crittografia-decrittografia in quanto causa molta CPU.

Quali altri meccanismi veloci e sicuri posso usare?

    
posta Novice User 07.03.2014 - 08:33
fonte

4 risposte

53

Stai violando uno dei tabù hashCode() ; stai usando il suo output come identificatore di chiave. È sbagliato.

Come vedi, l'output di hashCode() (nella sua implementazione predefinita) è un numero intero senza segno a 32 bit, ovvero circa 4 miliardi di hash unici. Sembra abbastanza? Beh, non così tanto. L'applicazione del problema del compleanno in questo caso mostra che con circa 77000 oggetti, hai circa il 50% di possibilità di collisione. 50% di possibilità che due oggetti abbiano lo stesso hashCode.

Un altro problema è che l'implementazione di hashCode() può cambiare da una versione di Java all'altra. Non è pensato per essere un identificatore permanente di un oggetto, quindi non c'è nulla che lo costringa a essere coerente tra le versioni.

Se insisti a utilizzare gli hash come identificatori di oggetti, allora è molto meglio avere il tuo metodo invece di hashCode() da utilizzare per i tuoi identificatori di chiave (ad esempio, getMySpecialHashKey() . Puoi usare qualcosa come MessageDigest.getInstance("SHA-256") a digita l'oggetto in una bella chiave a 256-bit.

La mia raccomandazione: elimina l'intera idea di hashing dell'oggetto e piuttosto genera un identificatore casuale per il tuo oggetto quando lo costruisci. Qualcosa sulla falsariga di (in Java)

SecureRandom secRand = new SecureRandom();
byte[] objIdBytes = new byte[16]; //128-bit
secRand.nextBytes(objIdBytes);
String objId = Base64.encodeBase64String(objIdBytes); //Here's your ID

Sembra anche che leghi l'accesso a un oggetto solo alla conoscenza della sua chiave. Anche questo è sbagliato. È necessario un modello appropriato basato sulle autorizzazioni con autenticazione e autorizzazione corrette.

    
risposta data 07.03.2014 - 09:40
fonte
30

Java hashCode() non è mai stato concepito per essere usato in questo modo. Non farlo mai! È persino legale (mentre non consigliato) che tutte le istanze di una classe restituiscano lo stesso hashCode. Il contratto in Java è "due oggetti considerati uguali devono avere lo stesso codice hash". Ne più ne meno. Ad esempio, sarebbe valido restituire hashcode 1 per tutti i numeri dispari e 0 per quelli pari.

hashCode viene utilizzato per una ricerca più rapida in raccolte come HashMap e le collisioni sono previste .

Molte classi definiscono la propria versione di hashCode() e, se conosci il codice, puoi spesso dire o indovinare facilmente l'hashcode.

Quindi, questo è assolutamente insicuro.

    
risposta data 07.03.2014 - 12:12
fonte
12

Non è crittograficamente sicuro, perché non fa parte dei suoi requisiti.

Il modo in cui è implementato hashCode è un dettaglio di implementazione fino alla JVM e può essere diverso per diversi tipi di oggetto (gli oggetti possono sovrascrivere il metodo hashCode e fornire un'implementazione personalizzata).

Lo scopo del codice hash Java è identificare gli oggetti quando li si posiziona nelle tabelle hash. Il suo requisito principale è la prestazione. Ha anche una lunghezza di soli 32 bit, che è troppo breve per evitare collisioni. Per gli scopi previsti (tabelle hash) due oggetti con lo stesso hash è solo un problema minore, ma identificare gli oggetti senza conflitti di ambiguità è un grosso problema.

Ma in generale non dovresti consentire ad alcun utente di accedere ad alcun oggetto solo perché conoscono gli oggetti codice hash. Utilizzare un adeguato sistema di gestione dei diritti. Utilizza account utente protetti da password in cui ogni utente ha un diverso set di parametri di autorizzazione. Quando l'utente tenta di accedere a un oggetto, controlla se le sue autorizzazioni gli consentono di farlo e rifiuta la richiesta quando non lo fa.

    
risposta data 07.03.2014 - 09:31
fonte
2

Certamente non è abbastanza sicuro per una situazione in cui i valori di indovinare possono rivelare informazioni.

Almeno alcuni degli override non sono nemmeno abbastanza sicuri da usare come codice hash di fronte a un input arbitrario selezionato dall'utente (è davvero facile fare un attacco hash-DoS contro qualsiasi cosa usando l'override String.hashCode() di Java ).

Nei casi in cui desideri un identificatore, ti consiglio di prendere un identificatore semplice (ad esempio una chiave numerica in un database, un numero intero incrementato a livello atomico che è una chiave in una tabella hash, ecc.) e quindi aggiungere un hash crittografico di tale e un sale.

Cioè, il tuo ID pubblicamente esposto sarebbe del modulo (in forma agnostica linguistica):

Concatenate(PrivateID, HexString(SHA256(UTF8Bytes(Concatenate(Salt, PrivateID)))))

(Potresti rimuovere parte dell'hash per un ID più piccolo al costo di tempo ridotto alla forza bruta).

Quindi l'ID privato può essere ottenuto come sottostringa e l'ID completo può essere nuovamente verificato. La procedura generale è anche facilmente trasferibile tra le lingue.

La manciata di cicli della CPU che costerà non avrà un grosso impatto sul resto del sistema, a meno che il tuo sistema sia così banale che non utilizzerai comunque molta CPU, quindi a meno che tu non sia eseguendo questo su qualcosa di veramente basso potere (come in, molto meno potente di un telefono economico) non sarà una preoccupazione.

Nei casi in cui in realtà si desidera utilizzare un codice hash come codice hash e gestire l'input selezionato dall'utente, quindi utilizzare un algoritmo hash seedable (ad esempio SpookyHash) e basare il seed in fase di avvio ( o meglio ancora, un mix di tempo di avvio e il tempo di creazione del contenitore hash). (Nulla da fare con gli hash crittografici, quindi possono essere molto più veloci, il rischio di sicurezza solo che questo evita è hash-DoSing).

    
risposta data 07.03.2014 - 18:07
fonte

Leggi altre domande sui tag