Quanto è unico l'UUID?


451

Quanto è sicuro utilizzare UUID per identificare in modo univoco qualcosa (lo sto usando per i file caricati sul server)? A quanto ho capito, si basa su numeri casuali. Tuttavia, mi sembra che, dato il tempo sufficiente, alla fine si ripeterebbe, solo per puro caso. Esiste un sistema migliore o un modello di qualche tipo per alleviare questo problema?


11
Per un valore abbastanza grande di "abbastanza tempo" :)

91
"Quanto è unico l'UUID?" Universalmente unico, credo. ;)
Miglia

29
E se non prevedi di sviluppare su Venere, un GUID dovrebbe essere sufficiente.
Skaffman,

1
maggiori dettagli e generatore qui: generatore di uuidi online
Dave,

2
"unico" significa non scontrarsi mai . Se ha qualche possibilità di scontrarsi, non è unico . Pertanto, per definizione, UUID non è unico e sicuro solo se si è preparati per potenziali collisioni indipendentemente dalla possibilità di collisioni. Altrimenti, il tuo programma è semplicemente errato. Puoi dire UUID come "quasi unico" ma non significa che sia "unico".
Eonil,

Risposte:


444

Molto sicuro:

si stima che il rischio annuale di una data persona sia colpito da un meteorite in una probabilità su 17 miliardi, il che significa che la probabilità è di circa 0,00000000006 (6 × 10 −11 ), equivalente alla probabilità di creare alcune decine di trilioni di UUID tra un anno e avere un duplicato. In altre parole, solo dopo aver generato 1 miliardo di UUID al secondo per i prossimi 100 anni, la probabilità di creare un solo duplicato sarebbe del 50% circa.

Avvertimento:

Tuttavia, queste probabilità valgono solo quando gli UUID sono generati usando entropia sufficiente. Altrimenti, la probabilità di duplicati potrebbe essere significativamente più elevata, poiché la dispersione statistica potrebbe essere inferiore. Laddove sono richiesti identificatori univoci per le applicazioni distribuite, in modo che gli UUID non si scontrino anche quando i dati provenienti da molti dispositivi vengono uniti, la casualità dei seed e dei generatori utilizzati su ogni dispositivo deve essere affidabile per la durata dell'applicazione. Laddove ciò non sia possibile, RFC4122 consiglia invece di utilizzare una variante dello spazio dei nomi.

Fonte: la sezione UUID casuale di duplicati dell'articolo di Wikipedia sugli identificatori universalmente univoci (il link conduce a una revisione da dicembre 2016 prima che la modifica abbia rielaborato la sezione).

Vedi anche la sezione corrente sullo stesso argomento sullo stesso articolo Identificatore univoco universale, Collisioni .


22
Mi piace questa parte di Wikipedia: Tuttavia, queste probabilità valgono solo quando gli UUID sono generati usando entropia sufficiente. Altrimenti, la probabilità di duplicati potrebbe essere significativamente più elevata, poiché la dispersione statistica potrebbe essere inferiore. Quindi qual è la reale possibilità di duplicare notando questa frase. Non possiamo creare veri numeri casuali sul computer, vero?
equipaggia il

6
In realtà, molto lavoro è stato dedicato alla ricerca di modi per introdurre quanta entropia ("casualità reale", immagino che la chiameresti) il più possibile in API con numeri casuali. Vedi en.wikipedia.org/wiki/Entropy_%28computing%29
broofa

4
Questa è in realtà una maggiore probabilità di collisione di quanto immaginassi. Paradosso di compleanno a, immagino.
Cameron,

Puoi confermare che l'utilizzo di UUID sarebbe sicuro tra le esecuzioni di un'applicazione? (ad esempio una sceneggiatura in pitone)
George Sp

ottimo esempio ...: D
NuttLoose,

151

Se per "tempo sufficiente" intendi 100 anni e li stai creando ad un tasso di un miliardo al secondo, allora sì, hai una probabilità del 50% di avere una collisione dopo 100 anni.


185
Ma solo dopo aver utilizzato fino a 256 exabyte di spazio di archiviazione per tali ID.
Bob Aman,

16
La cosa divertente è che potresti generarne 2 di fila identici, ovviamente a livelli da capogiro di coincidenza, fortuna e intervento divino, ma nonostante le insondabili probabilità, è ancora possibile! : D Sì, non accadrà. dico solo per il divertimento di pensare a quel momento in cui hai creato un duplicato! Screenshot video!
scalabl3

4
L'unicità è puramente dovuta alla casualità? O ci sono altri fattori? (ad es. timestamp, ip, ecc.)
Weishi Zeng

15
@TheTahaan Non è questo che significa casuale. Non significa "totalmente imprevedibile" - di solito seguono una sorta di distribuzione. Se lanci 10 monete, la possibilità di ottenere 2 teste, seguite da 3 code, seguite da 5 teste, è piuttosto bassa (2 ^ -10, circa 0,001). E 'veramente casuale, ma siamo assolutamente in grado di conoscere la possibilità di ottenere un risultato particolare. Non possiamo dire in anticipo se si sarà accadere.
Richard Rast,

5
Solo per spiegare ciò che questa implementazione ha fatto di sbagliato, stanno usando un UUID versione 1, che si basa su una combinazione di data / ora e indirizzo mac per la sua unicità. Tuttavia, se si generano UUID abbastanza velocemente, il timestamp non sarà ancora aumentato. In questo scenario, il tuo algoritmo di generazione UUID dovrebbe tenere traccia dell'ultimo timestamp utilizzato e incrementarlo di 1. Chiaramente non sono riusciti a fare quel passo. Tuttavia, tutti gli UUID versione 1 correttamente generati dalla stessa macchina in un breve periodo mostreranno evidenti somiglianze, ma dovrebbero essere ancora unici.
Bob Aman,

103

Esiste più di un tipo di UUID, quindi "quanto è sicuro" dipende dal tipo (che le specifiche UUID chiamano "versione") che stai utilizzando.

  • La versione 1 è basata sull'ora più l'UUID dell'indirizzo MAC. I 128 bit contengono 48 bit per l'indirizzo MAC della scheda di rete (assegnato in modo univoco dal produttore) e un orologio a 60 bit con una risoluzione di 100 nanosecondi. Quell'orologio si chiude nel 3603 d.C., quindi questi UUID sono al sicuro almeno fino ad allora (a meno che non siano necessari più di 10 milioni di nuovi UUID al secondo o qualcuno cloni la scheda di rete). Dico "almeno" perché l'orologio inizia il 15 ottobre 1582, quindi hai circa 400 anni dopo l'orologio prima che ci sia anche una piccola possibilità di duplicazioni.

  • La versione 4 è il numero casuale UUID. Ci sono sei bit fissi e il resto dell'UUID è di 122 bit di casualità. Vedi Wikipedia o altre analisi che descrivono quanto sia improbabile un duplicato.

  • La versione 3 utilizza MD5 e la versione 5 utilizza SHA-1 per creare quei 122 bit, anziché un generatore di numeri casuale o pseudo-casuale. Quindi, in termini di sicurezza, è come se la versione 4 fosse un problema statistico (purché tu assicurassi che l'algoritmo digest sia elaborato sia sempre unico).

  • La versione 2 è simile alla versione 1, ma con un orologio più piccolo, quindi andrà a finire molto prima. Ma poiché gli UUID versione 2 sono per DCE, non dovresti usarli.

Quindi per tutti i problemi pratici sono al sicuro. Se non ti senti a tuo agio nel lasciarlo alle probabilità (ad esempio, sei il tipo di persona preoccupata per la terra che viene distrutta da un grande asteroide nella tua vita), assicurati di usare un UUID versione 1 ed è garantito che sia unico ( nella tua vita, a meno che tu non preveda di superare il 3603 d.C.).

Quindi perché tutti non usano semplicemente gli UUID versione 1? Questo perché gli UUID versione 1 rivelano l'indirizzo MAC della macchina su cui è stato generato e possono essere prevedibili, due cose che potrebbero avere implicazioni di sicurezza per l'applicazione che utilizza quegli UUID.


1
L'impostazione predefinita di un UUID versione 1 presenta seri problemi quando vengono generati dallo stesso server per molte persone. L'UUID versione 4 è il mio valore predefinito poiché puoi scrivere rapidamente qualcosa per generarne uno in qualsiasi lingua o piattaforma (incluso javascript).
Justin Bozonier,

1
@Hoylen Ben spiegato! ma è necessaria molta esagerazione?
Dinoop paloli,

1
Teoricamente , è assegnato in modo univoco dal produttore.
OrangeDog,

4
Non è necessario generare 10 milioni di UUID versione 1 in un secondo per incontrare un duplicato; uno deve semplicemente generare un batch di 16.384 UUID all'interno dell'intervallo di un singolo "tick" al fine di traboccare il numero di sequenza. Ho visto che ciò accadeva con un'implementazione che si basava, ingenuamente, su una sorgente di clock che (1) aveva una granularità a livello di μs e (2) non era garantito essere monotonico (gli orologi di sistema non lo sono). Fai attenzione di chi usi il codice di generazione UUID e diffida soprattutto con i generatori UUID basati sul tempo. Sono difficili da ottenere correttamente, quindi sottoponili a test di carico prima di usarli.
Mike Strobel,

L'intervallo di tempo tra gli UUID v4 generati potrebbe portare a maggiori probabilità di collisione? Voglio dire in un'applicazione a traffico intenso, supponiamo che vengano generati migliaia di uuidi contemporaneamente, ci sono più possibilità di collisione rispetto a quando la stessa quantità di uuidi fosse generata in un periodo di tempo relativamente più lungo?
Jonathan,

18

La risposta a questa potrebbe dipendere in gran parte dalla versione UUID.

Molti generatori UUID utilizzano un numero casuale versione 4. Tuttavia, molti di questi usano Pseudo un generatore di numeri casuali per generarli.

Se un PRNG scarsamente seminato con un piccolo periodo viene utilizzato per generare l'UUID, direi che non è affatto sicuro.

Pertanto, è sicuro solo quanto gli algoritmi utilizzati per generarlo.

D'altro canto, se conosci la risposta a queste domande, penso che una versione 4 uuid dovrebbe essere molto sicura da usare. In effetti lo sto usando per identificare i blocchi su un file system a blocchi di rete e finora non ho avuto uno scontro.

Nel mio caso, il PRNG che sto usando è un tornado di mersenne e sto attento al modo in cui viene eseguito il seeding che proviene da più fonti tra cui / dev / urandom. Il twister di Mersenne ha un periodo di 2 ^ 19937 - 1. Ci vorrà molto tempo prima che io veda una ripetizione uuid.


14

Citando da Wikipedia :

Pertanto, chiunque può creare un UUID e utilizzarlo per identificare qualcosa con ragionevole sicurezza che l'identificatore non verrà mai utilizzato involontariamente da chiunque per qualcos'altro

Continua spiegando in dettaglio abbastanza bene quanto sia realmente sicuro. Quindi, per rispondere alla tua domanda: Sì, è abbastanza sicuro.


9

Concordo con le altre risposte. Gli UUID sono abbastanza sicuri per quasi tutti gli scopi pratici 1 , e sicuramente per i tuoi.

Ma supponiamo (ipoteticamente) che non lo siano.

Esiste un sistema migliore o un modello di qualche tipo per alleviare questo problema?

Ecco un paio di approcci:

  1. Usa un UUID più grande. Ad esempio, invece di 128 bit casuali, utilizzare 256 o 512 o ... Ogni bit aggiunto a un UUID di tipo 4 ridurrà la probabilità di una collisione della metà, supponendo che si disponga di una fonte affidabile di entropia 2 .

  2. Crea un servizio centralizzato o distribuito che generi UUID e registri tutti quelli che ha mai emesso. Ogni volta che ne genera uno nuovo, verifica che l'UUID non sia mai stato emesso prima. Tale servizio sarebbe tecnicamente semplice da attuare (credo) se assumessimo che le persone che gestivano il servizio fossero assolutamente affidabili, incorruttibili, ecc. Sfortunatamente, non lo sono ... specialmente quando esiste la possibilità che le organizzazioni di sicurezza dei governi interferiscano. Quindi, questo approccio è probabilmente poco pratico e potrebbe essere 3 impossibile nel mondo reale.


1 - Se l'unicità degli UUID determinasse se i missili nucleari sono stati lanciati nella capitale del tuo paese, molti dei tuoi concittadini non sarebbero convinti da "la probabilità è estremamente bassa". Da qui la mia qualifica "quasi tutto".

2 - Ed ecco una domanda filosofica per te. Qualcosa è mai veramente casuale? Come potremmo sapere se non lo fosse? L'universo come lo conosciamo è una simulazione? Esiste un Dio che potrebbe "modificare" le leggi della fisica per modificare un risultato?

3 - Se qualcuno è a conoscenza di documenti di ricerca su questo problema, si prega di commentare.


Voglio solo sottolineare che il metodo numero 2 sostanzialmente vanifica lo scopo principale dell'uso di UUID e potresti anche usare un classico ID numerato a quel punto.
Petr Vnenk,

Non sono d'accordo. Il difetto degli ID numerati sequenziali è che sono troppo facili da indovinare. Dovresti essere in grado di implementare il metodo 2 in un modo che rende difficile indovinare gli UUID.
Stephen C,

8

Gli schemi UUID generalmente utilizzano non solo un elemento pseudo-casuale, ma anche l'ora corrente del sistema e una sorta di ID hardware spesso univoco, se disponibile, come un indirizzo MAC di rete.

Il punto centrale dell'utilizzo di UUID è che ti fidi di fare un lavoro migliore nel fornire un ID univoco di quello che tu stesso potresti fare. Questa è la stessa logica alla base dell'utilizzo di una libreria di crittografia di terze parti piuttosto che della tua. Farlo da soli può essere più divertente, ma in genere è meno responsabile farlo.


5

L'ho fatto per anni. Non incorrere mai in un problema.

Di solito ho impostato i miei DB per avere una tabella che contiene tutte le chiavi e le date modificate e così via. Non ho mai incontrato un problema di chiavi duplicate.

L'unico inconveniente che ha è quando stai scrivendo alcune query per trovare rapidamente alcune informazioni che stai facendo un sacco di copia e incolla delle chiavi. Non hai più il minimo facile da ricordare ID.


5

Ecco uno snippet di prova per testare le sue unicità. ispirato al commento di @ scalabl3

La cosa divertente è che potresti generarne 2 di fila identici, ovviamente a livelli da capogiro di coincidenza, fortuna e intervento divino, ma nonostante le insondabili probabilità, è ancora possibile! : D Sì, non accadrà. dico solo per il divertimento di pensare a quel momento in cui hai creato un duplicato! Screenshot video! - scalabl3, 20 ottobre 15 alle 19:11

Se ti senti fortunato, seleziona la casella di controllo, controlla solo gli ID attualmente generati. Se desideri un controllo della cronologia, lascialo deselezionato. Si noti che ad un certo punto si potrebbe rimanere senza ram se lo si lascia deselezionato. Ho provato a renderlo compatibile con la CPU in modo da poterlo interrompere rapidamente quando necessario, basta premere nuovamente il pulsante di esecuzione dello snippet o uscire dalla pagina.

Math.log2 = Math.log2 || function(n){ return Math.log(n) / Math.log(2); }
  Math.trueRandom = (function() {
  var crypt = window.crypto || window.msCrypto;

  if (crypt && crypt.getRandomValues) {
      // if we have a crypto library, use it
      var random = function(min, max) {
          var rval = 0;
          var range = max - min;
          if (range < 2) {
              return min;
          }

          var bits_needed = Math.ceil(Math.log2(range));
          if (bits_needed > 53) {
            throw new Exception("We cannot generate numbers larger than 53 bits.");
          }
          var bytes_needed = Math.ceil(bits_needed / 8);
          var mask = Math.pow(2, bits_needed) - 1;
          // 7776 -> (2^13 = 8192) -1 == 8191 or 0x00001111 11111111

          // Create byte array and fill with N random numbers
          var byteArray = new Uint8Array(bytes_needed);
          crypt.getRandomValues(byteArray);

          var p = (bytes_needed - 1) * 8;
          for(var i = 0; i < bytes_needed; i++ ) {
              rval += byteArray[i] * Math.pow(2, p);
              p -= 8;
          }

          // Use & to apply the mask and reduce the number of recursive lookups
          rval = rval & mask;

          if (rval >= range) {
              // Integer out of acceptable range
              return random(min, max);
          }
          // Return an integer that falls within the range
          return min + rval;
      }
      return function() {
          var r = random(0, 1000000000) / 1000000000;
          return r;
      };
  } else {
      // From http://baagoe.com/en/RandomMusings/javascript/
      // Johannes Baagøe <baagoe@baagoe.com>, 2010
      function Mash() {
          var n = 0xefc8249d;

          var mash = function(data) {
              data = data.toString();
              for (var i = 0; i < data.length; i++) {
                  n += data.charCodeAt(i);
                  var h = 0.02519603282416938 * n;
                  n = h >>> 0;
                  h -= n;
                  h *= n;
                  n = h >>> 0;
                  h -= n;
                  n += h * 0x100000000; // 2^32
              }
              return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
          };

          mash.version = 'Mash 0.9';
          return mash;
      }

      // From http://baagoe.com/en/RandomMusings/javascript/
      function Alea() {
          return (function(args) {
              // Johannes Baagøe <baagoe@baagoe.com>, 2010
              var s0 = 0;
              var s1 = 0;
              var s2 = 0;
              var c = 1;

              if (args.length == 0) {
                  args = [+new Date()];
              }
              var mash = Mash();
              s0 = mash(' ');
              s1 = mash(' ');
              s2 = mash(' ');

              for (var i = 0; i < args.length; i++) {
                  s0 -= mash(args[i]);
                  if (s0 < 0) {
                      s0 += 1;
                  }
                  s1 -= mash(args[i]);
                  if (s1 < 0) {
                      s1 += 1;
                  }
                  s2 -= mash(args[i]);
                  if (s2 < 0) {
                      s2 += 1;
                  }
              }
              mash = null;

              var random = function() {
                  var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32
                  s0 = s1;
                  s1 = s2;
                  return s2 = t - (c = t | 0);
              };
              random.uint32 = function() {
                  return random() * 0x100000000; // 2^32
              };
              random.fract53 = function() {
                  return random() +
                      (random() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53
              };
              random.version = 'Alea 0.9';
              random.args = args;
              return random;

          }(Array.prototype.slice.call(arguments)));
      };
      return Alea();
  }
}());

Math.guid = function() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c)    {
      var r = Math.trueRandom() * 16 | 0,
          v = c == 'x' ? r : (r & 0x3 | 0x8);
      return v.toString(16);
  });
};
function logit(item1, item2) {
    console.log("Do "+item1+" and "+item2+" equal? "+(item1 == item2 ? "OMG! take a screenshot and you'll be epic on the world of cryptography, buy a lottery ticket now!":"No they do not. shame. no fame")+ ", runs: "+window.numberofRuns);
}
numberofRuns = 0;
function test() {
   window.numberofRuns++;
   var x = Math.guid();
   var y = Math.guid();
   var test = x == y || historyTest(x,y);

   logit(x,y);
   return test;

}
historyArr = [];
historyCount = 0;
function historyTest(item1, item2) {
    if(window.luckyDog) {
       return false;
    }
    for(var i = historyCount; i > -1; i--) {
        logit(item1,window.historyArr[i]);
        if(item1 == history[i]) {
            
            return true;
        }
        logit(item2,window.historyArr[i]);
        if(item2 == history[i]) {
            
            return true;
        }

    }
    window.historyArr.push(item1);
    window.historyArr.push(item2);
    window.historyCount+=2;
    return false;
}
luckyDog = false;
document.body.onload = function() {
document.getElementById('runit').onclick  = function() {
window.luckyDog = document.getElementById('lucky').checked;
var val = document.getElementById('input').value
if(val.trim() == '0') {
    var intervaltimer = window.setInterval(function() {
         var test = window.test();
         if(test) {
            window.clearInterval(intervaltimer);
         }
    },0);
}
else {
   var num = parseInt(val);
   if(num > 0) {
        var intervaltimer = window.setInterval(function() {
         var test = window.test();
         num--;
         if(num < 0 || test) {
    
         window.clearInterval(intervaltimer);
         }
    },0);
   }
}
};
};
Please input how often the calulation should run. set to 0 for forever. Check the checkbox if you feel lucky.<BR/>
<input type="text" value="0" id="input"><input type="checkbox" id="lucky"><button id="runit">Run</button><BR/>


Prova con un UUID RFC 4122 versione 1 (data-ora e indirizzo MAC).
zaph,

Una volta era velocissimo, fino a quando un aggiornamento di Chrome recentemente. Avevo notato lo stesso 4 settimane fa.
Tschallacka,

3

Non so se questo è importante per te, ma tieni presente che i GUID sono globalmente unici, ma non lo sono le sottostringhe dei GUID .


1
Tieni presente che il riferimento qui collegato parla degli UUID versione 1 (che portano le informazioni sul computer di generazione ecc. Nell'ID). La maggior parte delle altre risposte parla della versione 4 (che sono totalmente casuali). L'articolo di Wikipedia collegato sopra en.wikipedia.org/wiki/Universally_unique_identifier spiega i diversi tipi di UUID.
Kratenko,

3

Per UUID4 faccio in modo che ci siano circa tanti ID quanti sono i granelli di sabbia in una scatola a forma di cubo con lati lunghi 360.000 km. Quella è una scatola con i lati ~ 2 1/2 volte più lunghi del diametro di Giove.

Funzionando così qualcuno può dirmi se ho incasinato le unità:

  • volume di granello di sabbia 0,00947mm ^ 3 ( Guardiano )
  • UUID4 ha 122 bit casuali -> 5.3e36 valori possibili ( wikipedia )
  • volume di tanti granelli di sabbia = 5.0191e34 mm ^ 3 o 5.0191e + 25m ^ 3
  • lunghezza laterale della scatola cubica con quel volume = 3,69E8m o 369.000 km
  • diametro di Giove: 139.820 km (google)

In realtà immagino che questo presupponga un imballaggio del 100%, quindi forse dovrei aggiungere un fattore per quello!
Perso il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.