it-swarm.dev

Quanto è sicuro hashCode () di Java?

Secondo le nostre opinioni in un Java, attualmente sto usando hashCode come ID per gli oggetti, in modo che alla fine del server io possa recuperare lo stesso oggetto.

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

Quali altri meccanismi veloce ancora sicuro che posso usare?

21
Novice User

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

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

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

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

La mia raccomandazione: Abbandona l'intera idea di hashing dell'oggetto e genera piuttosto 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

Sembri anche vincolare l'accesso a un oggetto solo alla conoscenza della sua chiave. Anche questo è sbagliato. È necessario un modello basato sui permessi con autenticazione e autorizzazione adeguate.

54
Adi

Java hashCode() non è mai stato progettato per essere usato in questo modo. Non farlo mai! È persino legale (sebbene non raccomandato) per tutte le istanze di una classe restituire lo stesso hashCode. Il contratto in Java è "due oggetti considerati uguali devono avere lo stesso hashcode". Non più, non meno. Sarebbe ad esempio valido restituire l'hashcode 1 per tutti i numeri irregolari e 0 per anche quelli.

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

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

Quindi, questo è assolutamente insicuro.

30
Axel

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

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

Lo scopo di Java hashCode è quello di identificare gli oggetti quando li si inserisce nelle tabelle hash. Il suo requisito principale è le prestazioni. Ha anche una lunghezza di soli 32 bit, che è troppo corta per evitare collisioni. lo scopo previsto (tabelle hash) due oggetti con lo stesso hash è solo un problema minore, ma identificare oggetti senza collisioni di ambiguità è un grosso problema.

Ma in genere non dovresti permettere a nessun utente di accedere a nessun oggetto solo perché conoscono il codice hash degli oggetti. Utilizzare uno schema di gestione dei diritti adeguato. Utilizzare 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.

12
Philipp

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

Almeno alcune delle sostituzioni non sono nemmeno abbastanza sicure da usare come codice hash di fronte a input arbitrari selezionati 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 semplice identificatore (ad es. Una chiave numerica in un database, un numero intero incrementato atomicamente che è una chiave in una tabella hash, ecc.) E quindi aggiungere un hash crittografico di quello e un valore salt .

Cioè, il tuo ID esposto pubblicamente sarebbe nella forma (in forma agnostica della lingua):

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

(È possibile rimuovere parte dell'hash per un ID più piccolo a costo di tempo ridotto per la forza bruta).

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

La manciata di cicli della CPU questo costerà non avrà un grande impatto rispetto al resto del sistema, a meno che il tuo sistema sia così banale che non utilizzerai comunque molta CPU, quindi a meno che tu non lo stia eseguendo su qualcosa di veramente a bassa potenza (come in, molto meno potente di un telefono economico) non sarà un problema.

Nei casi in cui desideri effettivamente utilizzare un codice hash come codice hash e devi gestire l'input selezionato dall'utente, quindi utilizzare un algoritmo hash seedable (ad esempio SpookyHash) e basare il seed sul tempo di avvio (o meglio ancora , un mix di tempo di avvio e tempo di creazione del contenitore hash). (Nulla a che fare con gli hash crittografici, quindi possono essere molto più veloci; il solo rischio per la sicurezza che evita è hash-DoSing).

2
Jon Hanna