Versions d’UUID et quand les utiliser
(ntietz.com)- Les UUID comptent 8 versions, de v1 à v8 ; un numéro plus élevé ne signifie pas qu’une version est plus récente ou meilleure, mais que différents modes de génération sont définis dans la RFC 9562
- Dans la pratique, le choix se réduit généralement à v4 et v7 : v4 est le choix par défaut pour des identifiants aléatoires, tandis que v7 convient lorsqu’un tri par ordre de génération est nécessaire
- v1 et v6 utilisent les mêmes ingrédients, mais v6 réorganise les champs de façon à obtenir un ordre chronologique de génération lors du tri
- v3 et v5 créent des UUID en hachant des données d’entrée ; v3 utilise MD5, v5 utilise SHA-1, avec DNS et URL comme valeurs d’entrée possibles
- En pratique, il est pertinent d’utiliser v7 plutôt que v1 ou v6 si possible ; v5 si vous avez besoin d’un UUID basé sur des données d’entrée ; et v8 si vous avez besoin d’un UUID entièrement personnalisé
Modes de génération selon les versions d’UUID
- Les versions d’UUID vont de v1 à v8 et sont toutes définies dans la RFC 9562
-
UUID basés sur le temps
- UUID Version 1 est généré à partir d’un horodatage, d’un compteur monotone et d’une adresse MAC
- UUID Version 6 utilise les mêmes données que v1, mais en change l’ordre afin qu’un tri corresponde à l’ordre chronologique de génération
- UUID Version 7 est généré à partir d’un horodatage et de données aléatoires
-
UUID aléatoires et personnalisés
- UUID Version 4 est généré entièrement à partir de données aléatoires et correspond à peu près à la forme à laquelle beaucoup pensent quand on parle d’UUID
- UUID Version 8 est entièrement personnalisable, à l’exception des champs version/variant nécessaires à toutes les versions
-
UUID basés sur le hachage de données d’entrée
- UUID Version 3 est généré à partir du hachage MD5 des données fournies par l’utilisateur
- Les valeurs d’entrée candidates dans la RFC incluent DNS et URL
- UUID Version 5 est généré à partir du hachage SHA-1 des données fournies par l’utilisateur
- Comme pour v3, DNS et URL peuvent être des entrées candidates
- UUID Version 3 est généré à partir du hachage MD5 des données fournies par l’utilisateur
-
UUID réservés
- UUID Version 2 est réservé aux ID de sécurité et ne comporte pas de détails connus
Critères de choix en pratique
- Dans la plupart des cas, le choix se fait entre v4 ou v7
- Si vous avez simplement besoin d’un identifiant aléatoire, v4 est un bon choix par défaut
- Si l’ID doit pouvoir être trié, v7 peut être envisagé
- Par exemple, v7 peut être un candidat lorsqu’un UUID est utilisé comme clé de base de données
- v5 ou v8 sont plutôt utilisés lorsque l’on veut intégrer ses propres données dans l’UUID
- Pour ce type d’usage, l’utilisateur sait généralement déjà qu’il en a besoin
- Selon la RFC, v7 améliore v1 et v6 ; il faut donc utiliser v7 plutôt que v1 ou v6 si possible
- Si v1 ou v6 est absolument nécessaire, v6 peut être utilisé
- v2 est réservé à des usages de sécurité non spécifiés
- v3 a été remplacé par v5, qui utilise un hachage plus fort, et les cas où v3 est nécessaire sont probablement déjà connus de l’utilisateur
1 commentaires
Avis de Hacker News
Dire qu’il n’y a pas de détails sur UUID v2, c’est vrai seulement si l’on s’en tient à la lecture du RFC notoirement obscur : https://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#t...
On n’en rencontre presque jamais, mais il existe aussi des UUID version 0. Ils méritent d’être mentionnés, car ils sont à l’origine des bits réservés qui ont ensuite permis de définir d’autres « versions » de façon compatible. J’ai résumé les recherches associées dans ma bibliothèque UUID : https://github.com/okeeblow/DistorteD/blob/NEW%E2%80%85SENSA...
J’ai décidé de les prendre en charge parce que je trouve ça élégant, mais il me reste encore à trancher la gestion du rollover de date et la façon de traiter les UID Apollo plus anciens.
Je commence à travailler sur un RFC informatif qui aiderait les gens à comprendre les types d’UUID historiques définis dans l’espace Variant 0-7. Si vous voulez participer à la discussion ou relire la formulation, voir https://github.com/yocto/draft-yocto-uuid.
Les détails se trouvaient en deux minutes. Il suffisait de cliquer sur le lien de l’article vers la section du RFC 9562 qui définit DCE, puis sur le premier lien de ce paragraphe vers la spécification, et enfin de chercher « UUID » pour arriver à l’annexe A : tout y est.
Le nom, « Universal Unique Identifier », prête à confusion, mais le contenu nécessaire est bien là. Ce serait bien de cliquer au moins sur les liens que l’on met dans son propre article.
Dans le contexte, comme les autres versions sont décrites comme étant générées à partir de certains éléments précis, la phrase parle clairement du second point. Elle est un peu ambiguë, mais difficile de dire qu’elle induit vraiment en erreur.
Cela dit, l’annexe était intéressante à lire, comme un instantané de l’époque.
J’aimerais bien qu’il existe une norme d’UUID courts du genre
73WakrfVbNJBaAmhQtEeDvoubK7nP9xM.Strictement parlant, ce ne seraient sans doute pas des UUID, puisqu’ils pourraient entrer en collision quelque part, mais je voudrais un ensemble standard d’ID aléatoires tout en restant assez courts pour être mémorisables.
S’il n’existe pas de norme plus populaire, c’est probablement parce qu’il faut renoncer à quelque chose. 128 bits donnent un risque de collision faible dans presque tous les usages, mais plus on réduit la taille, plus il faut raisonner sur le contexte concret et les conséquences d’une collision, ce qui rend la standardisation difficile. Avec d’autres encodages comme base64 ou base85, on peut faire plus court, mais on sacrifie des aspects comme la sensibilité à la casse ou la compatibilité sûre avec les URL : https://github.com/ulid/spec
Ce n’est qu’une autre représentation du même UUID, réversible. Un UUID étant au final une valeur de 128 bits, il s’agit davantage d’une notation alternative que d’une vraie transformation.
On perd l’avantage de tri monotone présent dans certaines versions d’UUID, mais base58 est sûr pour les URL et ne contient pas de caractères spéciaux. Les valeurs peuvent toujours être stockées en binaire. Par exemple, dans Postgres, on peut utiliser
byteaau lieu d’une colonne texte.La discussion est ici : https://github.com/uuid6/new-uuid-encoding-techniques-ietf-d...
Le timestamp des UUID v7 a beaucoup changé les choses pour Databend. Nous l’utilisons pour retrouver rapidement les fichiers de métadonnées par timestamp dans AWS S3, ce qui accélère nettement des opérations comme vacuum.
PR : https://github.com/datafuselabs/databend/pull/16049
Le grand avantage des UUID triés chronologiquement est leur meilleure localité. Quand on ajoute une nouvelle entrée à un index, cela revient le plus souvent à l’ajouter à la fin, ce qui peut coûter moins cher que des insertions aléatoires. Cela dit, cela peut aussi augmenter la contention ; on peut donc envisager un hybride avec quelques bits aléatoires avant le timestamp pour créer des « shards » triés. Les lectures portent aussi souvent sur les données récentes, donc avoir ces données regroupées et bien présentes en cache est utile.
Il est difficile de comprendre l’objectif de uuid2. Je ne savais même pas qu’il existait davantage de types de ce genre, et j’ai vu uuid2 pour la première fois en demandant à Xandr de supprimer mes données personnelles : https://news.ycombinator.com/item?id=40913915
Même en lisant Wikipédia, je ne comprends pas bien pourquoi, après avoir créé quelque chose appelé « identifiant unique universel », on a prévu plusieurs types, dont certains ont été conçus à l’origine pour permettre de remonter jusqu’au PC. Je me demande si mélanger une partie du code MAC rend uuid2 plus proche de l’aléatoire, ou s’il y a une autre raison. Du point de vue de la protection des données personnelles, je me demande aussi pourquoi on ne pourrait pas simplement utiliser de longs identifiants avec un très grand nombre de caractères possibles, afin de rendre la probabilité de collision pratiquement nulle.
N’importe quelles deux machines pouvaient produire le même UID/UUID pour les mêmes deux entrées, et le destinataire du message identifié pouvait reconstituer les composants d’origine à partir de l’identifiant. Comme ils étaient conçus comme des étiquettes pour des messages temporaires, les deux dimensions étaient le temps et l’ID matériel ; au début, il s’agissait du numéro de série Apollo, puis plus tard de l’adresse matérielle Ethernet, entre autres.
Je pense qu’une grande partie de la confusion vient du fait que, dans les premières implémentations d’AEGIS, les ingénieurs d’Apollo ont commencé à utiliser des UID « canned », c’est-à-dire statiques et bien connus, pour l’identification dans le système de fichiers. Avec le temps, l’usage courant des UUID s’est complètement déplacé : d’identifiants temporaires où les doublons étaient intentionnels, ils sont devenus des identifiants canned où il faut éviter les collisions ; et les deux dimensions sont devenues l’aléatoire et encore l’aléatoire.
L’histoire est plus complexe. Microsoft a recruté l’une des personnes clés d’Apollo pour créer MSRPC pour Windows NT, ce qui a aussi donné naissance aux GUID. Les GUID ont une disposition des champs différente de celle des UUID et, contrairement à ce qu’affirment de nombreuses sources, ils ne sont pas en endianité mixte. Microsoft utilise volontiers des GUID canned non seulement pour identifier les messages RPC temporaires, mais aussi pour à peu près tout ce qui nécessite des identifiants bien connus : classes COM, codecs média, etc. Exemple : https://gix.github.io/media-types/
Désolé de lier deux fois mon dépôt dans le même fil de commentaires, mais j’ai commencé à résumer cette histoire dans le README de ma bibliothèque UUID, et il faudrait que je m’y remette. Apollo a démarré en 1980, tandis que le brouillon de la RFC UUID de Leach/Salz n’est arrivé qu’en 1998 ; il manque donc énormément de choses dans les standards modernes : https://github.com/okeeblow/DistorteD/blob/NEW%E2%80%85SENSA...
UUID v4 n’est rien d’autre qu’un générateur d’octets aléatoires avec des tirets placés à des positions définies. Il n’est pas indispensable de l’utiliser : on peut générer soi-même des octets aléatoires et économiser de l’espace.
Cela réduit aussi les tirets inutiles, les informations de version, etc.
C’est un peu comme une adresse IPv4, qui est un nombre de 32 bits, tandis que la notation « quatre groupes séparés par des points » n’est qu’une de ses représentations. Si vous pensez à un UUID comme à un format de chaîne, vous vous trompez déjà sur le concept le plus fondamental des UUID. Même si l’on veut seulement un identifiant aléatoire, je trouve élégant qu’un UUID aléatoire contienne quelques bits de drapeau indiquant « ceci est censé être aléatoire ». C’est utile lorsqu’on tombe sur un identifiant isolé, sans contexte.
On peut débattre de l’utilité de créer des espaces de noms différents entre plusieurs méthodes de génération, mais un générateur aléatoire ordinaire n’a qu’une chance sur 16 de produire un UUIDv4 valide. Bien sûr, si vous voulez écrire votre propre générateur d’UUID, régler correctement les bits est trivial.
En Go,
uuid.New().String()suffit, alors que lire des données aléatoires aveccrypto/randpuis les convertir en base64 ou en hexadécimal demande plus de lignes et d’efforts.Je déconseille d’utiliser les versions basées sur MAC. En théorie, cela peut concerner toutes les versions sauf v4 et v7, mais v1 est la pire.
v3 a aussi le problème que MD5 est gravement cassé.
Je ne connaissais pas les détails au-delà de la version 4, mais ce qui manque vraiment et serait utile serait probablement une méthode utilisant des données SHA256 et un compteur, un peu dans l’esprit de PBKDF2.
Cela pourrait servir d’identifiant dérivé préservant la confidentialité, et permettre aussi de prouver de façon souple qu’un UUID donné a été dérivé d’une certaine graine.
Sinon, vous finirez par vouloir une sortie plus longue.
Il suffit d’utiliser v7.
C’est maintenant au tour des experts sécurité de dire non.
Dans beaucoup de cas d’usage, il serait très utile de pouvoir retraiter les données et obtenir le même ID, mais je ne connais pas de manière standard d’y parvenir.