Wie einzigartig ist uniqid?

76

Diese Frage ist nicht wirklich ein Problem bei der Suche nach einer Lösung, sondern eher eine Frage der einfachen Neugier. Die PHP-Uniqid-Funktion verfügt über ein Entropie-Flag, um die Ausgabe "eindeutiger" zu machen. Ich habe mich gefragt, wie wahrscheinlich es ist, dass diese Funktion mehr als einmal dasselbe Ergebnis liefert, wenn more_entropy wahr ist, im Gegensatz dazu, wenn dies nicht der Fall ist. Mit anderen Worten, wie eindeutig ist Uniqid, wenn more_entropy aktiviert ist, im Vergleich zu deaktiviert? Gibt es Nachteile, wenn more_entropy ständig aktiviert ist?

GordonM
quelle
3
Wenn Sie etwas möchten, das immer einzigartig ist, müssen Sie eine GUID implementieren . So ziemlich alles andere wird irgendwann kollidieren, da die Funktion nur so viel Entropie enthält. Zum Beispiel ergibt uniqidmit more_entropyset nur etwa 92 Bit Entropie (23 Hexbit). Um zu verstehen, warum das nicht gut für die Einzigartigkeit ist, siehe Das Geburtstagsproblem ...
ircmaxell
@ircmaxell danke für den Hinweis auf das Geburtstagsproblem, es ist ziemlich interessant. Es sollte definitiv in der Antwort erwähnt werden.
Petr Peller
2
uniqid () ist keine Hash-Funktion, daher gilt das Geburtstagsproblem nicht dafür. Es hat jedoch seine Schwachstellen.
Joel Mellon
@ircmaxell woher kommt diese Nummer? more_entropybeträgt ungefähr 30 Bit Entropie (neun Dezimalstellen), der Mikrosekunden-Teil ist ungefähr 20 (sechs Dezimalstellen), woher kommt der Rest? Sie müssten die Sekunde aus einem Bereich von 100.000 Jahren auswählen, um 42 Entropiebits zu erhalten.
Tgr

Antworten:

36

Update, März 2014:

Erstens ist es wichtig zu beachten, dass dies uniqideine Fehlbezeichnung ist, da keine eindeutige ID garantiert wird.

Gemäß der PHP-Dokumentation :

WARNUNG!

Diese Funktion erstellt keine zufälligen oder unvorhersehbaren Zeichenfolgen. Diese Funktion darf nicht aus Sicherheitsgründen verwendet werden. Verwenden Sie kryptografisch sichere Zufallsfunktionen / Generatoren und kryptografisch sichere Hash-Funktionen, um eine unvorhersehbare sichere ID zu erstellen.

Und

Diese Funktion generiert keine kryptografisch sicheren Token. Ohne zusätzliche Parameter unterscheidet sich der Rückgabewert kaum von microtime () . Wenn Sie kryptografisch sichere Token generieren müssen, verwenden Sie openssl_random_pseudo_bytes () .


Wenn Sie mehr Entropie auf true setzen, wird ein eindeutigerer Wert generiert. Die Ausführungszeit ist jedoch länger (wenn auch zu einem winzigen Grad).

Wenn auf TRUE gesetzt, fügt uniqid () am Ende des Rückgabewerts zusätzliche Entropie hinzu (unter Verwendung des kombinierten linearen Kongruenzgenerators), was die Wahrscheinlichkeit erhöht, dass das Ergebnis eindeutig ist.

Beachten Sie die Linie increases the likelihood that the result will be uniqueund nicht, dass dies die Eindeutigkeit garantiert .

Sie können "endlos" bis zu einem gewissen Punkt nach Einzigartigkeit streben und diese mithilfe einer beliebigen Anzahl von Verschlüsselungsroutinen verbessern, indem Sie Salze und dergleichen hinzufügen - dies hängt vom Zweck ab.

Ich würde empfehlen, die Kommentare zum Hauptthema von PHP zu lesen, insbesondere:

http://www.php.net/manual/en/function.uniqid.php#96898

http://www.php.net/manual/en/function.uniqid.php#96549

http://www.php.net/manual/en/function.uniqid.php#95001

Was ich empfehlen würde, ist herauszufinden, warum Sie Eindeutigkeit benötigen, aus Sicherheitsgründen (dh um eine Verschlüsselungs- / Verschlüsselungsroutine zu ergänzen)? Auch Wie einzigartig braucht es zu sein? Schauen Sie sich zum Schluss die Geschwindigkeitsüberlegung an. Die Eignung ändert sich mit den zugrunde liegenden Überlegungen.

SW4
quelle
1
Die wichtigste Lektion bei diesen Funktionskommentaren ist, dass uuid für sich genommen eine sehr gefährliche Kennung ist, die als Cookie / Client-lesbare ID übergeben werden kann, aber als lokale / geschützte eindeutige ID einige gute Verwendungsmöglichkeiten hat, nämlich Geschwindigkeit. 2,5 Cent.
DrPerdix
3
Ich weiß noch nicht, ob dies offensichtlich war, aber ich verwende uniqid(oder es sind Derivate) nichts für Sicherheitsfragen. PHP bietet eine ganze Reihe von kryptosicheren Zufallsgeneratoren, wie zum Beispiel : openssl_random_pseudo_bytes. Bitte verwenden Sie das richtige Werkzeug für den Job.
Halcyon
1
Angenommen, es werden keine 2 Dateien in derselben Mikrosekunde gespeichert, wäre ein Unix-Mikrosekunden-Zeitstempel für jede Datei eindeutig.
CMCDragonkai
Es ist statistisch gesehen unwahrscheinlich, dass Sie eine Kollision bekommen, aber nicht unmöglich. Setzen Sie Ihre einzigartige Generation in ein do{} while(collision). Ich verwende diesen Ansatz zum Beispiel beim Generieren von Pfaden für hochgeladene Dateien.
Afilina
2
Ich bin mir nicht sicher, warum diese Antwort akzeptiert wurde. Einzigartig! = Zufällig / unvorhersehbar
Gadelat
16

Dinge sind nur dann einzigartig, wenn Sie überprüfen, ob sie noch nicht vorhanden sind. Es spielt keine Rolle, mit welcher Funktion Sie eine 'zufällige' Zeichenfolge oder ID generieren - wenn Sie nicht überprüfen, ob es sich nicht um ein Duplikat handelt, besteht immer diese Chance ..;)

Während uniqid auf der aktuellen Zeit basiert, gilt der obige Warnhinweis weiterhin - es hängt nur davon ab, wo Sie diese "eindeutigen IDs" verwenden. Der Hinweis auf all dies ist, wo es "einzigartiger" sagt. Einzigartig ist einzigartig ist einzigartig. Wie man etwas mehr oder weniger Einzigartiges haben kann, ist für mich etwas verwirrend!

Wenn Sie wie oben prüfen und all diese Dinge kombinieren, erhalten Sie etwas, das sich der Einzigartigkeit nähert, aber alles hängt davon ab, wo die Schlüssel verwendet werden und im Kontext. Hoffentlich hilft das!

dmp
quelle
10
Es gibt einen großen Unterschied zwischen "Die Wahrscheinlichkeit einer Kollision ist eins zu zehntausend" und "Die Änderung einer Kollision ist geringer als wenn jeder einzelne Benutzer des Programms gleichzeitig vom Blitz getroffen wird". Ein 128-Bit-Wert, der von einem guten RNG mit einem guten Startwert erzeugt wird, ist so nahe daran, "wirklich" einzigartig zu sein, dass es angesichts der unglaublich hohen Kosten, etwas nachweislich (und unvorhersehbares) Einzigartiges zu erhalten, keine Rolle spielt .
Michael Borgwardt
6
Nur um Ihren Standpunkt zu verdeutlichen @Michael: Für 128 Bit müsste jeder in den USA (300 Millionen) für ungefähr einen Tag 1 Million Zahlen pro Sekunde generieren, um eine 50% ige Chance auf eine Kollision zu erhalten ... Für 512 Bits, Sie würden jeden Körper auf der Erde (7 Milliarden Menschen) brauchen, um für die nächsten 10^47Jahre jeweils 1 Billion Zahlen pro Sekunde zu generieren, nur um eine 50% ige Chance auf eine Kollision zu haben ... Also ja, mit einer ausreichend hohen Obergrenze Auf der Zufallszahl UND einem ausreichend guten RNG können Sie die Einzigartigkeit nur mit Zufälligkeit simulieren ...
ircmaxell
1
Ich stimme voll und ganz Ihren idealen Weltbeispielen wie oben zu. Die Chancen sind minimal. Die Zufälligkeit ist jedoch in den Implementierungen, auf die in der ursprünglichen Frage Bezug genommen wurde, nicht perfekt, und ich behaupte, dass die Domäne, in der diese eindeutige Nummer verwendet wird, wichtig ist. Wenn Sie 1000 Server hatten, die jeweils "eindeutige" IDs basierend auf den Mikrotzeiten ausführten und davon ausgegangen sind, dass sie "nur weil" eindeutig sind, können Sie sich irgendwann verbrennen. Ignorieren Sie alle Macken im Code .. Fehler oder was auch immer. Der Unterschied besteht hier zwischen Realität und Theorie, und deshalb überprüfen wir;)
dmp
5
"Das Prinzip, kleine Mengen endlicher Unwahrscheinlichkeit zu erzeugen, indem einfach die Logikschaltungen eines Bambleweeny 57 Sub-Meson Brain an einen Atomvektorplotter angeschlossen werden, der in einem starken Brownian Motion-Produzenten (sagen wir eine schöne heiße Tasse Tee) suspendiert ist, war natürlich gut verstanden . "
dmp
1
@ircmaxell: Der Haken ist, dass diese Zahlen echte Zufälligkeit und damit ein echtes RNG erfordern . Sie konnten es nicht einmal mit einem PRNG mit> 128 Bit internem Status simulieren, es sei denn, Sie hatten auch die Möglichkeit, es mit einem eindeutigen / zufälligen> 128-Bit-Wert zu versehen. Aber genau das müssen Sie lösen! Und alles andere garantiert praktisch Kollisionen. Dieselben 300 Millionen Menschen rand()hätten, wenn sie den beschissenen Bestand ihres Compilers verwenden , bei der ersten Iteration eine Kollisionswahrscheinlichkeit von > 90% . Wenn Sie Einzigartigkeit benötigen , ist sogar eine Kollisionswahrscheinlichkeit von 0,001% zu groß.
CHao
10

Aus den Diskussionen über die Funktion auf der PHP-Handbuchseite:

Wie andere unten erwähnen, gibt diese Funktion ohne Präfix und ohne "hinzugefügte Entropie" einfach den UNIX-Zeitstempel mit hinzugefügtem Mikrosekundenzähler als Hex-Zahl zurück. Es ist mehr oder weniger nur microtime () in hexit-Form.

[...]

Beachten Sie auch, dass uniqid () in einer Windows-Umgebung möglicherweise nur den UNIX-Zeitstempel mit einer Auflösung von einer Sekunde liefert, da microtime () nur auf Systemen funktioniert, auf denen gettimeofday ()> vorhanden ist, was Windows nativ NICHT tut.

Mit anderen Worten, ohne "more_entropy" ist die Funktion absolut schrecklich und sollte niemals verwendet werden, Punkt. Gemäß der Dokumentation verwendet das Flag einen "kombinierten linearen Kongruenzgenerator", um "Entropie hinzuzufügen". Nun, das ist ein ziemlich schwaches RNG. Also würde ich diese Funktion komplett überspringen und etwas verwenden, das auf mt_rand basiert, mit einem guten Startwert für Dinge, die nicht sicherheitsrelevant sind, und SHA-256 für Dinge, die nicht sicherheitsrelevant sind.

Michael Borgwardt
quelle
7

Ohne das Flag more_unique wird der Unix-Zeitstempel mit einem Mikrosekundenzähler zurückgegeben. Wenn also zwei Aufrufe mit derselben Mikrosekunde getätigt werden, geben sie dieselbe 'eindeutige' ID zurück.

Von dort ist es eine Frage, wie wahrscheinlich das ist. Die Antwort ist nicht sehr, aber nicht in abschätzbarem Maße. Wenn Sie eine eindeutige ID benötigen und diese häufig generieren (oder mit Daten arbeiten, die an anderer Stelle generiert wurden), rechnen Sie nicht damit, dass diese absolut eindeutig ist.

Reese Moore
quelle
21
Ob Sie es glauben oder nicht, es ruft tatsächlich usleep (1) auf, um sicherzustellen, dass dies niemals passiert!
Eli
2
@Eli nicht sicher, ob Trolling oder nicht, aber das ist eindeutig nicht der Fall, da ich Duplikate bekomme, die dies ausführen: for ($ i = 0; $ i <10; $ i ++) echo uniqid (). "\ n";
djule5
3
@ djule5 Nein, nicht trolling: github.com/php/php-src/blob/… Führen Sie möglicherweise eine sehr alte Version von PHP aus oder befinden Sie sich auf einer Plattform für usleep, die es nicht gibt?
Eli
@Eli interessant haha ​​danke für die Quelle! Ich verwende PHP 5.5.11, aber ich bin unter Windows auf diesem Entwicklungscomputer ... das erklärt es wahrscheinlich! Also ist es definitiv nicht so einzigartig unter Windows ...
djule5
1
@ user5542121 Sie haben beschlossen, stattdessen nicht usleep und poll time aufzurufen, da usleep "dazu führen kann, dass der Kernel einen anderen Prozess plant und eine Pause von ca. 10 ms verursacht" ~ github.com/php/php-src/blob/PHP-7.2.12/ ext / standard /…
x3ns
5

Das relevante Bit aus dem Quellcode ist

if (more_entropy) {
    uniqid = strpprintf(0, "%s%08x%05x%.8F", prefix, sec, usec, php_combined_lcg() * 10);
} else {
    uniqid = strpprintf(0, "%s%08x%05x", prefix, sec, usec);
}

So more_entropyfügt neun etwas zufällig Dezimalstellen ( php_combined_lcg()liefert einen Wert in (0,1)) - , die 29,9 Bits der Entropie ist, Tops (in Wirklichkeit wahrscheinlich weniger als LCG ist kein kryptographisch sicheren Pseudozufallszahlengenerator).

Tgr
quelle