UUID-Versionen und wann man sie verwendet
(ntietz.com)- Es gibt 8 UUID-Versionen von v1 bis v8; eine höhere Zahl bedeutet nicht, dass sie neuer oder besser ist, sondern dass in RFC 9562 unterschiedliche Erzeugungsverfahren definiert sind
- In der Praxis läuft die Auswahl meist auf v4 und v7 hinaus: v4 ist der Standard für zufällige IDs, v7 eignet sich, wenn eine Sortierung nach Erstellungszeit erforderlich ist
- v1 und v6 verwenden dieselben Bestandteile, aber bei v6 ist die Feldreihenfolge so geändert, dass eine Sortierung der Erstellungszeit entspricht
- v3 und v5 erzeugen UUIDs durch Hashing der Eingabedaten; v3 verwendet MD5, v5 SHA-1, und mögliche Eingabewerte sind unter anderem DNS und URL
- Wenn möglich, sollte man statt v1·v6 v7 verwenden; wenn eine eingabedatenbasierte UUID benötigt wird, ist v5 sinnvoll, und für vollständig benutzerdefinierte UUIDs kommt v8 in Betracht
Erzeugungsverfahren nach UUID-Version
- UUID-Versionen gibt es von v1 bis v8, und sie sind alle in RFC 9562 definiert
-
Zeitbasierte UUIDs
- UUID Version 1 wird aus Zeitstempel, monotonem Zähler und MAC-Adresse erzeugt
- UUID Version 6 verwendet dieselben Daten wie v1, ändert aber die Reihenfolge so, dass beim Sortieren die Erstellungszeit erhalten bleibt
- UUID Version 7 wird aus Zeitstempel und Zufallsdaten erzeugt
-
Zufällige und benutzerdefinierte UUIDs
- UUID Version 4 wird vollständig aus Zufallsdaten erzeugt und entspricht am ehesten dem, was viele sich unter einer UUID vorstellen
- UUID Version 8 ist vollständig benutzerdefiniert, abgesehen von den version/variant-Feldern, die für alle Versionen erforderlich sind
-
UUIDs auf Basis eines Eingabedaten-Hashs
- UUID Version 3 wird aus dem MD5-Hash der vom Benutzer bereitgestellten Daten erzeugt
- In der RFC sind DNS und URL als mögliche Eingabewerte genannt
- UUID Version 5 wird aus dem SHA-1-Hash der vom Benutzer bereitgestellten Daten erzeugt
- Wie bei v3 kommen auch hier DNS und URL als Eingabekandidaten infrage
- UUID Version 3 wird aus dem MD5-Hash der vom Benutzer bereitgestellten Daten erzeugt
-
Reservierte UUIDs
- UUID Version 2 ist für Sicherheits-IDs reserviert; bekannte Details dazu gibt es nicht
Praktische Auswahlkriterien
- In den meisten Fällen fällt die Wahl auf v4 oder v7
- Wenn einfach nur eine zufällige ID benötigt wird, ist v4 die naheliegende Standardwahl
- Wenn die ID sortierbar sein soll, kann v7 sinnvoll sein
- Zum Beispiel kann v7 ein Kandidat sein, wenn UUIDs als Datenbankschlüssel verwendet werden
- v5 oder v8 sind eher für Fälle gedacht, in denen eigene Daten in die UUID eingebettet werden sollen
- In solchen Fällen wissen Nutzer meist bereits, dass sie genau diesen Typ benötigen
- Laut RFC verbessert v7 v1 und v6, daher sollte man nach Möglichkeit v7 statt v1·v6 verwenden
- Wenn v1 oder v6 zwingend erforderlich sind, kann v6 verwendet werden
- v2 ist für einen nicht näher spezifizierten Sicherheitszweck reserviert
- v3 wurde durch v5 mit stärkerem Hash ersetzt; auch wenn v3 benötigt wird, wissen Nutzer das oft bereits
1 Kommentare
Meinungen auf Hacker News
Dass es keine Details zu UUID v2 gebe, gilt nur, wenn man ausschließlich den notorisch unklaren RFC liest: https://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#t...
Man wird ihr fast nie begegnen, aber es gibt auch eine Version-0-UUID. Sie ist erwähnenswert, weil von ihr die reservierten Bits stammen, durch die später andere „Versionen“ kompatibel definiert werden konnten. Die zugehörige Recherche habe ich in meiner UUID-Bibliothek zusammengetragen: https://github.com/okeeblow/DistorteD/blob/NEW%E2%80%85SENSA...
Weil ich sie cool fand, habe ich beschlossen, sie zu unterstützen; allerdings muss ich noch festlegen, wie Datums-Rollover und die noch ältere Apollo-UID-Behandlung funktionieren sollen.
Ich beginne gerade mit der Arbeit an einem informativen RFC zu den historischen UUID-Typen, die im Variant-Raum 0–7 definiert sind, damit Leute sie besser verstehen. Wer mitdiskutieren oder Formulierungen prüfen möchte, kann hier schauen: https://github.com/yocto/draft-yocto-uuid
Die Details ließen sich in zwei Minuten finden. Im Artikel dem Link zum DCE-Definitionsabschnitt von RFC 9562 folgen, über den ersten Link in diesem Absatz zur Spezifikation gehen, nach „UUID“ suchen und zu Anhang A springen — dort steht alles
Der Name ist verwirrend „Universal Unique Identifier“, aber die benötigten Inhalte sind vollständig vorhanden. Es wäre gut, wenn man wenigstens die Links im eigenen Artikel selbst anklickt
Im Kontext wird beschrieben, dass andere Versionen aus bestimmten Elementen erzeugt werden, daher bezieht sich der Satz eindeutig auf Letzteres. Der Satz ist zwar etwas unklar, aber schwerlich irreführend
Der Anhang las sich trotzdem interessant, fast wie eine Momentaufnahme von damals
Ein Standard für kurze UUIDs wie
73WakrfVbNJBaAmhQtEeDvoderbK7nP9xMwäre schönStreng genommen wären es wohl keine UUIDs, weil sie irgendwo kollidieren könnten, aber ich hätte gern eine standardisierte Kombination für zufällige IDs, die kurz genug sind, um sie sich zu merken
Ich denke, es gibt keinen populäreren Standard, weil man immer auf etwas verzichten muss. 128 Bit bedeuten für fast alle Zwecke ein geringes Kollisionsrisiko, aber je kleiner man wird, desto stärker muss man die konkrete Situation und die Folgen von Kollisionen berücksichtigen, was eine Standardisierung erschwert. Andere Encodings wie base64 oder base85 wären kürzer, opfern aber Dinge wie Groß-/Kleinschreibung oder URL-Sicherheit: https://github.com/ulid/spec
Das ist nur eine andere Darstellung derselben UUID und reversibel. Eine UUID ist letztlich ein 128-Bit-Wert; es ist also eher eine alternative Notation als eine echte Umwandlung
Damit verliert man den Vorteil monotoner Sortierung mancher UUID-Versionen, aber base58 ist URL-sicher und enthält keine Sonderzeichen. Die Werte lassen sich weiterhin binär speichern. In Postgres könnte man zum Beispiel statt einer Textspalte
byteaverwendenDie Diskussion ist hier zu finden: https://github.com/uuid6/new-uuid-encoding-techniques-ietf-d...
Der Zeitstempel von UUID v7 war für Databend eine große Veränderung. Er wird genutzt, um Metadatendateien in AWS S3 schnell anhand des Zeitstempels zu finden, wodurch Operationen wie vacuum deutlich schneller werden
PR: https://github.com/datafuselabs/databend/pull/16049
Der große Vorteil zeitlich sortierbarer UUIDs liegt in der besseren Lokalität. Beim Einfügen neuer Einträge in einen Index landen sie meist am Ende, was günstiger sein kann als zufällige Inserts. Allerdings kann dadurch auch mehr Contention entstehen; daher kann sich ein Hybrid lohnen, bei dem einige Zufallsbits vor den Zeitstempel gesetzt werden, um sortierte „Shards“ zu bilden. Auch Lesezugriffe konzentrieren sich oft auf aktuelle Daten, daher ist es nützlich, wenn aktuelle Daten an einem Ort liegen und gut im Cache landen
Der Zweck von uuid2 ist schwer zu verstehen. Ich wusste nicht einmal, dass es noch mehr solcher Typen gibt, und habe uuid2 zum ersten Mal gesehen, als ich Xandr um die Löschung meiner personenbezogenen Daten bat: https://news.ycombinator.com/item?id=40913915
Selbst nach dem Lesen von Wikipedia verstehe ich nicht wirklich, warum man einen „universell eindeutigen Identifikator“ schafft und dann mehrere Typen hat, von denen einige ursprünglich sogar so gemacht waren, dass sie bis zum PC zurückverfolgbar sind. Ich frage mich, ob das Beimischen eines Teils des MAC-Codes uuid2 zufälliger macht oder ob es einen anderen Grund gibt. Aus Datenschutzsicht frage ich mich auch, ob man nicht einfach lange Identifikatoren mit sehr vielen möglichen Zeichen verwenden kann, um die Wahrscheinlichkeit von Duplikaten praktisch auszuschließen.
Zwei beliebige Maschinen konnten für dieselben zwei Eingaben dieselbe UID/UUID erzeugen, und der Empfänger der identifizierten Nachricht konnte den Identifikator wieder in seine ursprünglichen Bestandteile zurückführen. Da sie als Labels für flüchtige Nachrichten entworfen wurden, waren die zwei Dimensionen Zeit und Hardware-ID; zunächst wurden Apollo-Seriennummern verwendet, später unter anderem Ethernet-Hardwareadressen.
Ein großer Teil der Verwirrung kommt meiner Ansicht nach daher, dass Apollo-Ingenieure in der frühen AEGIS-Implementierung begannen, „canned“, also statische und wohlbekannte UIDs, zur Dateisystem-Identifikation zu verwenden. Mit der Zeit verschob sich der übliche Einsatz von UUIDs vollständig: von flüchtigen Identifikatoren, bei denen Kollisionen beabsichtigt waren, hin zu canned Identifikatoren, bei denen Kollisionen vermieden werden müssen; und die zwei Dimensionen wurden zu Zufall und nochmals Zufall.
Die Geschichte ist noch komplizierter. Microsoft stellte eine der Schlüsselfiguren von Apollo ein, um MSRPC für Windows NT zu entwickeln, und so entstand auch GUID. GUIDs haben eine andere Feldanordnung als UUIDs und sind, anders als viele Quellen behaupten, nicht Mixed-Endian. Microsoft verwendet canned GUIDs gern nicht nur zur Identifikation flüchtiger RPC-Nachrichten, sondern für COM-Klassen, Medien-Codecs und fast alles andere, was wohlbekannte Identifikatoren braucht. Beispiel: https://gix.github.io/media-types/
Entschuldigung, dass ich im selben Kommentarbereich zweimal auf mein Repository verlinke, aber im README meiner UUID-Bibliothek habe ich begonnen, diese Geschichte aufzuschreiben, und sollte daran weiterarbeiten. Apollo begann 1980, und der Leach/Salz-Entwurf für den UUID-RFC erschien erst 1998; in modernen Standards fehlt also enorm viel: https://github.com/okeeblow/DistorteD/blob/NEW%E2%80%85SENSA...
UUID v4 ist lediglich ein Generator für Zufallsbytes, der Bindestriche an festgelegten Positionen einfügt. Man muss sie nicht unbedingt verwenden; wenn man selbst Zufallsbytes erzeugt, kann man Platz sparen.
Auch unnötige Bindestriche und Versionsinformationen entfallen.
Ähnlich wie eine IPv4-Adresse eine 32-Bit-Zahl ist und die „vier durch Punkte getrennten Blöcke“ nur eine ihrer Darstellungen sind. Wenn man UUIDs als String-Format betrachtet, hat man schon das grundlegendste Konzept von UUIDs falsch verstanden. Selbst wenn man nur einen zufälligen Identifikator möchte, finde ich es gut, dass eine zufällige UUID ein kleines Flag-Bit enthält, das sagt: „Das ist als zufällig gedacht.“ Das ist nützlich, wenn man nur einen kontextlosen Identifikator findet.
Ob es nützlich ist, zwischen verschiedenen Erzeugungsmethoden unterschiedliche Namensräume zu schaffen, kann man diskutieren, aber ein gewöhnlicher Zufallsgenerator erzeugt nur mit einer Wahrscheinlichkeit von 1/16 eine gültige UUIDv4. Wenn man natürlich selbst einen UUID-Generator schreiben möchte, ist es trivial, die Bits korrekt zu setzen.
In Go reicht
uuid.New().String(), während es mehr Zeilen und Aufwand braucht, um mitcrypto/randZufallsdaten zu lesen und in Base64 oder Hex umzuwandeln.Von MAC-basierten Versionen würde ich abraten. Theoretisch kann das alles außer v4 und v7 betreffen, aber v1 ist am schlimmsten.
Bei v3 gibt es außerdem das Problem, dass MD5 stark gebrochen ist.
Die Details außer Nummer 4 kannte ich nicht, aber wirklich nützlich wäre wohl eine Methode mit SHA256-Daten und einem Zähler. Ähnlich wie PBKDF2.
Das könnte ein abgeleiteter Identifikator sein, der personenbezogene Daten schützt, und man könnte lose nachweisen, dass eine bestimmte UUID aus einem bestimmten Seed abgeleitet wurde.
Ansonsten wird man wahrscheinlich eine längere Ausgabe haben wollen.
Man kann einfach v7 verwenden.
Jetzt sind die Sicherheitsexperten dran zu sagen, dass man das nicht sollte.
Für viele Anwendungsfälle wäre es sehr nützlich, beim erneuten Verarbeiten von Daten dieselbe ID erzeugen zu können, aber ich kenne keinen standardisierten Weg, das zu erreichen.