Java UUID.randomUUID () o SecureRandom per il segmento id sull'URL?

6

Nella costruzione di un sistema basato su Java che richiede identificatori univoci nell'URL, è UUID.randomUUID() o SecureRandom una scelta migliore?

Più specificamente, una chiamata a POST /items restituirà un 201 Created con una Location al /items/{id} appena creato dove {id} è una stringa casuale e l'URL è destinato ad essere utilizzato da richieste HTTP anonime per un finestra temporale limitata.

Questo codice restituisce una stringa di 22 caratteri (ad esempio B-KEPLFdWNZ4JTUnnEq3Og ) con 128 bit di casualità.

SecureRandom random = new SecureRandom();
byte bytes[] = new byte[16];
random.nextBytes(bytes);
Encoder encoder = Base64.getUrlEncoder().withoutPadding();
String token = encoder.encodeToString(bytes);
System.out.println(token);

UUID.randomUUID () è un "Fabbrica statica per recuperare un UUID di tipo 4 (generato a caso in modo casuale) L'UUID viene generato utilizzando un generatore di numeri pseudo casuali crittograficamente strong." Questo codice restituisce una stringa di 36 caratteri (ad esempio f0803ce7-8e3d-421a-8126-e5a0bd0a865f ) con 122 bit di casualità.

UUID randomUUID = UUID.randomUUID();
System.out.println(randomUUID);

Questi identificatori verranno anche mantenuti in un database relazionale come tipo di lunghezza fissa CHAR .

    
posta Kevin Hakanson 24.10.2016 - 22:55
fonte

2 risposte

8

In termini di quantità di bit casuali, sì.

Guardando il origine per la generazione casuale UUID di Java , puoi vedere che effettivamente utilizzano la classe SecureRandom per generare i byte non elaborati. Quindi, la 'qualità' della tua casualità non cambierà.

Il fatto che tu abbia altri 6 bit, tecnicamente, rende più difficile la forza bruta di un duplicato. articolo di Wikipedia su UUID ha una buona descrizione della matematica che c'è dietro. Per citarla:

[A]fter generating 1 billion UUIDs every second for the next 100 years, the probability of creating just one duplicate would be about 50%

Se questi link stanno per scadere, diciamo, 24 ore, questa è una cosa molto piccola di cui preoccuparsi, e questo è solo con 122 bit.

Ora, più bit renderanno più difficile per un utente malintenzionato forzare una collisione con la forza? Sicuro! Ne vale la pena? Forse ... ma forse no. Solo tu puoi davvero decidere cosa è giusto per il tuo caso d'uso.

Quando arrivi al punto in cui la forza brutale di una collisione richiederebbe, in media, più tempo del tempo stimato per la morte termica dell'universo, potrebbe essere un po 'esagerato. Si sta arrivando al punto di dover preoccuparsi di più degli hacker compromettendo la sicurezza dello storage più del brute forcing (e, onestamente, anche con gli UUID, avrai questo problema). In definitiva, la difficoltà del brute forcing non importa se riescono a trovare un altro modo. Se sei davvero preoccupato, lo storage è economico: memorizza le stringhe a 256 bit generate con una SecureRandom e chiamala buona, ma assicurati hai sicurezza adeguata su tutto il resto, o è inutile.

    
risposta data 24.10.2016 - 23:17
fonte
8

Bene, in linea di principio, gli UUID e gli RNG crittografici promettono due cose diverse:

  1. Gli UUID promettono bassa probabilità di duplicati ;
  2. Gli RNG crittografici promettono imprevedibilità a un avversario malevolo .

Se il n. 2 è un problema, mi assicurerei di utilizzare un RNG crittografico. Ad esempio, se sei preoccupato che un malintenzionato che può richiedere un sacco di UUID in un breve intervallo di tempo potrebbe apprendere informazioni sufficienti a prevedere quelle date alle richieste di altri utenti.

Come succede, il metodo UUID.randomUUID() di Java utilizza un RNG crittografico, quindi dovrebbe essere sicuro al riguardo. Ma il rischio è che gli sviluppatori che più tardi guardano il tuo codice potrebbero non capire che il tuo intento include scelte casuali crittografiche sicure, e non solo unicità. Ad esempio, qualcuno potrebbe riscrivere quel particolare modulo usando un altro linguaggio o una libreria UUID che non usa un RNG crittografico ed esporre a attacchi basati su predizione che intendevi escludere. Quindi, se la sicurezza crittografica fosse davvero un fattore importante, proverei a scrivere il codice in un modo che lo renda ovvio, utilizzando SecureRandom esplicitamente. (Il codice di sicurezza deve essere molto chiaro!)

Se tutto ciò che mi importava era l'unicità invece della sicurezza, allora andrei avanti e userei UUID.randomUUID() .

    
risposta data 25.10.2016 - 02:09
fonte

Leggi altre domande sui tag