Gli UUID collidono? Pattern di implementazione e operazione che invitano duplicati
· Aggiornato il: · Go Komura · UUID, Identificatori, Sistemi distribuiti, Data Design, Implementazione
Hai usato UUID come chiavi primarie, e un giorno compare duplicate key.
In quel momento, c’è una buona probabilità che qualcuno dica: “Quindi gli UUID collidono.”
In pratica, però, la maggior parte dei duplicati UUID non è un problema della specifica UUID stessa, ma casi in cui l’implementazione o le operazioni rompono le condizioni di generazione che la specifica assume. Sotto RFC 9562, UUIDv4 ha 122 bit di spazio casuale, e UUIDv7 è definito assumendo che i 74 bit esterni al timestamp siano usati per casualità o contatori che forniscono unicità. UUIDv8, d’altra parte, è descritto esplicitamente come implementation-specific, e l’unicità non deve essere assunta.123
Anche la libreria standard Python documenta che uuid4() è generato usando un metodo criptograficamente sicuro, quindi, finché “si usa un’implementazione corretta nel modo normale”, le garanzie lato UUID sono piuttosto forti.4
In questo articolo organizziamo i pattern tipici in cui operazioni o implementazioni errate fanno collidere gli UUID, insieme alle misure per prevenire la ricorrenza. Il contenuto è basato su RFC 9562, la documentazione ufficiale Python e la documentazione ufficiale PostgreSQL come verificabili a marzo 2026.546
1. La conclusione prima di tutto
Per riassumere subito, questi sono i pattern pericolosi.
| Pattern | Cosa succede | Prima contromisura |
|---|---|---|
| Creare a mano valori simili a UUIDv4 con seed fisso o PRNG debole | La stessa sequenza viene riprodotta in un altro processo o nodo | Usa l’API UUID standard del SO / runtime |
| Portare lo stato del generatore dopo fork, snapshot VM o clone container | Lo stato casuale o del contatore torna indietro e compaiono duplicati | Re-seed dopo fork, re-inizializza dopo clone, rivedi la gestione dello stato persistente |
| Usare UUIDv3 / v5 pensando che restituiscano “un nuovo ID ogni volta” | Lo stesso UUID viene rigenerato dallo stesso namespace e stesso nome | Capisci che sono ID deterministici e limitane l’uso |
| Implementare UUIDv1 / v6 / v7 / v8 a mano gestendo male rollback orologio o nodo/contatore | I duplicati diventano probabili con generazione ad alta frequenza o tra nodi | Usa librerie esistenti e riduci i generatori custom |
| Troncare gli UUID a metà o schiacciarli in un altro formato | Butti tu stesso via l’unicità 128-bit originale | Conserva e confronta a lunghezza piena |
| Non mettere UNIQUE / PRIMARY KEY sul lato DB | I duplicati entrano silenziosamente e l’analisi root-cause si ritarda | Mantieni un vincolo di unicità nello storage |
In breve, piuttosto che “l’UUID ha colliso”, di solito è che l’unicità che ti aspettavi dall’UUID è stata intaccata da qualche parte nel design.
2. Sospetta prima generazione e operazioni, non la “matematica degli UUID”
Le discussioni sugli UUID diventano confuse perché le proprietà differiscono per versione.
- UUIDv4 è basato su casualità. Sotto RFC 9562, i 122 bit diversi da versione / variant sono riempiti con dati casuali.1
- UUIDv7 ha una struttura che ordina bene cronologicamente; oltre a un timestamp Unix in millisecondi, il resto è composto da casualità o da un contatore accuratamente seedato.2
- UUIDv3 / v5 sono basati su nome. Dato lo stesso namespace e lo stesso nome canonico, produrre lo stesso UUID è il comportamento corretto.7
- UUIDv8 è per uso sperimentale e vendor-specific, e la sua unicità è implementation-specific. La RFC dice esplicitamente che non si deve assumere unicità.3
Quindi anche se dici “usiamo UUID”, la storia cambia completamente a seconda che si tratti di
uuid4()della libreria standard- un
timestamp + randomfatto in casa uuid5(namespace, name)- o un formato custom che sembra solo UUIDv8.
flowchart TD
A[Trovato un UUID duplicato] --> B{Dove è venuto davvero lo stesso valore}
B --> C[Generatore debole]
B --> D[Stato riavvolto]
B --> E[Uso errato di UUID basati su nome]
B --> F[Troncato al momento dello storage]
B --> G[Nessun vincolo di unicità sul DB]
C --> H[Errore di implementazione]
D --> H
E --> H
F --> H
G --> H
In pratica, partire dal lato destro di questo diagramma è più veloce.
3. Pattern 1: Chiamarlo UUIDv4 mentre si usa un PRNG debole
Questo è il più comune.
- Costruire 128 bit con un PRNG generico equivalente a
Math.random() - Seedare all’avvio con
time()o il PID - Assemblare a mano “32 cifre esadecimali che sembrano formato UUID”
Può sembrare un UUID, ma se la sorgente casuale è debole, la stessa sequenza viene riprodotta in un altro processo o nodo.
RFC 9562 raccomanda di usare un CSPRNG, sia per l’unicità UUID che per l’impossibilità di indovinare. Questa è una raccomandazione (SHOULD), quindi eccezioni possono essere progettate per alcuni casi d’uso, ma se crei a mano UUID con un PRNG generico devi essere in grado di spiegare perché. Inoltre, afferma che lo stato del CSPRNG dovrebbe essere re-seedato correttamente al cambiamento di stato come un fork di processo.8
Anche Python uuid.uuid4() è documentata come generazione di UUID casuali in modo criptograficamente sicuro.4
La conclusione pratica qui è semplice.
- Non creare UUID a mano
- Non giocherellare con seed casuali a mano
- Usa la libreria standard o un’implementazione ampiamente usata così com’è
Tenere un generatore custom “perché è leggero” o “perché l’abbiamo sempre usato” è ciò che costa di più in seguito.
4. Pattern 2: Riavvolgere lo stato del generatore tramite fork, snapshot o clone
La seconda cosa più pericolosa è operazioni in cui lo stato del generatore viene duplicato o riavvolto.
RFC 9562 raccomanda esplicitamente di re-seedare dopo fork, e spiega che implementazioni senza storage stabile devono generare sequenze di clock, contatori e dati casuali più frequentemente, il che aumenta la probabilità di duplicati.89
Da questo deriva naturalmente una linea pratica.
- Ripristinare più istanze della stessa immagine dopo aver fatto uno snapshot VM
- Un generatore custom che parte dallo stesso stato iniziale ogni volta che un’immagine container si avvia
- Condividere lo stato PRNG o contatore tra fork di worker
Sotto queste operazioni, la sequenza di generazione UUID può essere riprodotta involontariamente. La RFC non dice letteralmente “gli snapshot sono pericolosi”, ma questa è una cautela pratica molto reale che si ricava dalle sue note sul re-seed dopo fork e sulla gestione dello stato del generatore.89
Le contromisure appaiono così.
- Non conservare a lungo lo stato custom del generatore UUID
- Re-inizializza subito dopo fork / clone / restore
- Dove possibile, appoggiati a implementazioni che pescano casualità fornita dal SO ogni volta
- Per generatori ad alta frequenza, documenta esplicitamente la gestione dello stato e le specifiche di re-seed
5. Pattern 3: Leggere male UUIDv3 / v5 come “un nuovo ID ogni volta”
UUIDv3 / v5 non sono ID casuali che resistono alla collisione. Sono ID deterministici che possono rigenerare lo stesso ID dallo stesso nome.
RFC 9562 afferma che UUID generati dallo stesso nome in forma canonica all’interno dello stesso namespace devono essere uguali.7 Quindi con un uso come il seguente, i duplicati non sono un incidente — sono il comportamento specificato.
- Usare
uuid5(NAMESPACE_URL, "https://example.com/users/42")come “assegnazione di ID fresco” ogni volta - Emettere ID da un namespace condiviso tra tutti i clienti più un’email, senza mettere il tenant nel namespace
- Assumere che ri-emettere lo stesso nome logico a ogni retry dia un ID diverso
Viceversa, se la canonicalizzazione del nome è inconsistente, ottieni UUID diversi per lo stesso soggetto. La RFC sottolinea ripetutamente la gestione della rappresentazione canonica.710
Quel che conta in questa famiglia sono tre cose:
- UUIDv3 / v5 non sono “assegnazione di ID senza collisioni” ma “stesso input, stesso ID”
- Non lasciare vago il design del namespace
- Specifica esplicitamente la canonicalizzazione dei nomi
6. Pattern 4: Implementare UUID basati sul tempo o UUIDv8 a mano
UUIDv1 / v6 / v7 / v8 sono pericolosi da imitare solo per l’aspetto.
6.1 Gestire node o clock sequence con noncuranza in UUIDv1 / v6
Sotto RFC 9562, UUIDv6 è un UUIDv1 con campi riordinati progettato per migliorare la località DB, e tratta clock sequence e node. La RFC porta anche molteplici cautele sulla resistenza alle collisioni di node in ambienti distribuiti e sulla conservazione dello stato.11912
Inoltre, la RFC arriva a dire che con l’avvento di macchine virtuali e container, l’unicità degli indirizzi MAC non può più essere garantita.5
Quindi design come
- assumere “è un indirizzo MAC, quindi deve essere unico”
- replicare un node ID cotto in un’immagine
- resettare la clock sequence a un valore fisso a ogni riavvio
sono pericolosi.
6.2 Costruire UUIDv7 a mano ignorando rollover del contatore o rollback dell’orologio
UUIDv7 è abbastanza pratico, ma la RFC è accurata su monotonicità e gestione del contatore sotto generazione ad alta frequenza. Afferma inoltre esplicitamente che le implementazioni non devono restituire consapevolmente duplicati su rollback dell’orologio o rollover del contatore.213
Il che significa che implementazioni come
- emettere grandi volumi nello stesso millisecondo senza un design del contatore
- continuare a generare senza fare nulla quando l’orologio va indietro
- processi multipli che inizializzano ciascuno lo stesso contatore interno in modo indipendente
sono rischiose.
6.3 Trattare UUIDv8 alla leggera, come se fosse “la nuova specifica UUID”
UUIDv8 sembra comodo, ma RFC 9562 è piuttosto chiara: l’unicità di UUIDv8 è implementation-specific e non deve essere assunta.3
Quindi un “UUID proprietario dell’azienda” che
- incorpora un timestamp
- incorpora uno shard ID
- incorpora qualche significato di business
- e riempie il resto con qualunque casualità
significa che quel documento di design è in sé la tua specifica di unicità UUID. È troppo pericoloso introdurlo senza revisione.
7. Pattern 5: Accorciare l’UUID lungo la strada
Anche se la generazione è corretta, le cose possono rompersi nello stage di storage o confronto.
Esempi tipici:
- Usare solo i primi 8 caratteri come surrogato di foreign key
- Schiacciare un UUID 128-bit in un intero 64-bit
- Una colonna stringa troppo corta, così la coda viene tagliata
- Trattare la rappresentazione accorciata usata nei log o a schermo come chiave unica
Quel che conta qui è che cambiare la rappresentazione non è di per sé cattivo.
- Rimuovere i trattini
- Normalizzare a lower / upper case
- Conservare come 16 byte binari
Trasformazioni come queste, che non scartano nessuno dei 128 bit, vanno bene. Pericolose sono le trasformazioni che raschiano via la stessa sostanza dell’unicità.
In particolare, un design in cui è stato creato un “short ID amico dell’umano” separato e poi silenziosamente ha iniziato a prevalere sul vero UUID è incline agli incidenti.
8. Pattern 6: Nessun vincolo di unicità sul lato DB
E questo è particolarmente importante.
Anche se gli UUID sono sufficientemente resistenti alle collisioni, se non puoi tollerare davvero duplicati, la destinazione di storage dovrebbe portare anche un vincolo di unicità.
La documentazione ufficiale di PostgreSQL spiega che un vincolo unique garantisce che il valore di una colonna o gruppo di colonne sia unico in tutta la tabella, e che una primary key è un identificatore di riga unico e not null.6
Anche RFC 9562 dice che, sebbene gli UUID possano fornire un’unicità sufficiente in pratica, l’unicità globale vera non può mai essere garantita assolutamente, e che per usi in cui l’impatto di una collisione è alto andrebbero prese contromisure più forti.14
In pratica, questa combinazione è la baseline.
- Usa gli UUID come ID che difficilmente collidono
- Mantieni UNIQUE / PRIMARY KEY nel DB come ultima linea di difesa
- Progetta retry / idempotenza / incident logging per il caso duplicato
Usare UUID e omettere vincoli di unicità non sono la stessa cosa.
9. Una checklist pratica
Infine, ecco un modulo che puoi usare direttamente per adozione o audit.
- Verifica se stai generando UUID da solo
Se puoi passare ad API standard come
uuid4()/uuid7(), fallo per primo. - Decidi la versione UUID come parte della specifica Dichiara esplicitamente che v4/v7 sono basati su casualità, v3/v5 sono deterministici, e v8 è una specifica custom.
- Fai l’inventario di come vengono gestiti seed e stato del generatore Assicurati che lo stesso stato non venga portato oltre fork, riavvio worker, snapshot o clone.
- Conferma che a storage venga conservata la lunghezza piena Non usare confronti per prefisso o display accorciati come chiave effettiva.
- Metti UNIQUE / PRIMARY KEY nel DB Un UUID è un meccanismo che abbassa la probabilità; non è un vincolo in sé.
- Rendi i duplicati osservabili Non ingoiare gli errori di chiave duplicata; rendi tracciabile quale generatore / nodo / deployment li ha prodotti.
10. Riassunto
Gli incidenti di collisione UUID di solito iniziano non perché l’UUID sia debole, ma perché l’implementazione o le operazioni rompono le assunzioni su cui l’UUID si basa.
- Creare a mano con casualità debole
- Riavvolgere lo stato dopo fork o snapshot
- Usare UUID basati su nome per assegnazione di ID freschi
- Implementare casualmente v7 o v8
- Troncare lungo la strada scartando l’unicità
- Rimuovere il vincolo di unicità sul lato DB
Farne anche solo uno equivale quasi a costruire attivamente una situazione in cui le collisioni diventano probabili.
Quando trovi un duplicato, quello che dovresti sospettare per primo non è la matematica degli UUID, ma il generatore, la gestione dello stato, il formato di storage e il design dei vincoli. Guarda in quell’ordine, e la causa di solito si restringe rapidamente.
11. Articoli correlati
- Come usare FileSystemWatcher in sicurezza - Pitfall di eventi persi, notifiche duplicate e rilevamento del completamento
- Fondamenti di controllo esclusivo in integrazione basata su file - Best practice per lock file e claim atomici
12. Riferimenti
-
IETF RFC 9562, Section 5.4 UUID Version 4. Sugli 122 bit di spazio casuale di UUIDv4. ↩ ↩2
-
IETF RFC 9562, Section 5.7 UUID Version 7. Sul design di timestamp, bit casuali e contatori di UUIDv7. ↩ ↩2 ↩3
-
IETF RFC 9562, Section 5.8 UUID Version 8. Sull’unicità implementation-specific di UUIDv8 e sul fatto che non deve essere assunta. ↩ ↩2 ↩3
-
Python 3.14 documentation,
uuidmodule. Suuuid4()generazione criptograficamente sicura, comportamento deterministico diuuid5(), e proprietà diuuid7()/uuid8(). ↩ ↩2 ↩3 -
IETF RFC 9562, Universally Unique IDentifiers (UUIDs). Il documento di base per il formato UUID, ogni versione e le best practice complessive. ↩ ↩2
-
PostgreSQL documentation, Constraints. Sul garantire unicità tramite vincoli UNIQUE e PRIMARY KEY. ↩ ↩2
-
IETF RFC 9562, Section 6.5 Name-Based UUID Generation. Sullo stesso namespace + stesso nome che danno lo stesso UUID, e sull’importanza della canonicalizzazione. ↩ ↩2 ↩3
-
IETF RFC 9562, Section 6.9 Unguessability. Sull’uso di CSPRNG e re-seed dopo fork. ↩ ↩2 ↩3
-
IETF RFC 9562, Section 6.3 UUID Generator States. Sulla gestione dello storage stabile e dello stato del generatore. ↩ ↩2 ↩3
-
IETF RFC 9562, Section 5.5 UUID Version 5. Sulla specifica degli UUID basati su nome costruiti da namespace più nome canonico. ↩
-
IETF RFC 9562, Section 5.6 UUID Version 6. Su UUIDv6: node / clock sequence / località DB. ↩
-
IETF RFC 9562, Section 6.4 Distributed UUID Generation. Sulla resistenza alle collisioni di node in ambienti distribuiti. ↩
-
IETF RFC 9562, Section 6.2 Monotonicity and Counters. Sulle cautele di rollback dell’orologio, rollover del contatore e generazione batch. ↩
-
IETF RFC 9562, Sections 6.7 and 6.8. Sul ragionamento dietro resistenza alle collisioni e unicità globale. ↩
Articoli correlati
Articoli recenti con gli stessi tag per approfondire argomenti vicini.
10 minacce maggiori alla sicurezza informatica 2026 — Come leggere la classifica e cosa dovrebbero difendere le PMI
Nelle '10 minacce maggiori alla sicurezza informatica 2026' dell'IPA, gli attacchi ransomware occupano il primo posto per l'undicesimo an...
Il Sussidio per investimenti di risparmio del lavoro può pagare lo spostamento degli ordini fax sul web? — Come ragionare sull'investimento per l'ordine sistema nella categoria generale
Spostare la ricezione ordini fax sul web e automatizzarne l'import può essere un candidato per il Sussidio per investimenti di risparmio ...
Non dimenticare di decidere 'in quanti secondi è abbastanza veloce' — Organizzare i requisiti non funzionali con il Non-Functional Requirements Grade dell'IPA
Le dispute del tipo 'è troppo lento' o 'non ci aspettavamo quella reazione al guasto' di solito risalgono a requisiti non funzionali che ...
Come gestire un progetto di sviluppo sistema finanziato da un sussidio — Lavorare all'indietro dalla data di decisione sul sussidio e le pratiche per scrivere il business plan
Un progetto di sviluppo sistema finanziato da un sussidio procede in modo diverso da uno ordinario. Questo articolo tratta, in termini pr...
Cosa dovrebbero sapere anche i committenti di siti web — usare la 'Guida per rendere sicuro il proprio sito web' dell'IPA come checklist
Con quale standard controllare la sicurezza del sito web aziendale? Questo articolo spiega le 11 vulnerabilità e contromisure trattate ne...
Argomenti correlati
Queste pagine collocano l’argomento in un contesto più ampio di servizi e decisioni.
Argomenti tecnici Windows
Portale su sviluppo Windows, analisi dei problemi e valorizzazione delle risorse esistenti.
Servizi collegati all’argomento
L’articolo è direttamente collegato ai servizi seguenti.
Consulenza tecnica e revisione del progetto
Le domande sulle collisioni UUID spaziano non solo sulla specifica ma su sorgenti di casualità, operazioni snapshot, vincoli DB e idempotenza, quindi valgono la pena come design review o consulenza tecnica.
Analisi dei bug e delle cause
Negli incidenti reali di ID duplicati bisogna determinare se la colpa è dell'UUID stesso o di implementazione e operazioni, quindi organizzare gli angoli di indagine e il design di prevenzione della ricorrenza è essenziale.
Domande frequenti
Domande che ricorrono nelle consulenze sull’argomento dell’articolo.
- Gli UUID collidono effettivamente in pratica?
- Quando generati con un'implementazione corretta usata nel modo normale, le collisioni sono estremamente improbabili: sotto RFC 9562, UUIDv4 ha 122 bit di spazio casuale, e librerie standard come Python uuid4() usano generazione criptograficamente sicura. La maggior parte degli incidenti reali di duplicati non è un fallimento della specifica UUID, ma casi in cui implementazione o operazioni hanno rotto le condizioni di generazione che la specifica assume. Quando trovi un duplicato, sospetta prima il generatore, la gestione dello stato, il formato di storage e il design dei vincoli, prima della matematica.
- Quali errori di implementazione causano UUID duplicati?
- I pattern ricorrenti sono: creare a mano valori simili a UUIDv4 con un PRNG generico o un seed fisso, che riproduce la stessa sequenza in un altro processo o nodo; portare lo stato del generatore attraverso fork, snapshot VM o clone di container facendo tornare indietro lo stato casuale o del contatore; implementare a mano UUID basati sul tempo (v1, v6, v7) senza gestire il rollback dell'orologio o il rollover del contatore; troncare gli UUID a un breve prefisso o schiacciarli in 64 bit, buttando via l'unicità; e omettere il vincolo UNIQUE sul lato database così che duplicati entrino silenziosamente.
- Perché UUIDv3 e UUIDv5 restituiscono lo stesso UUID ogni volta?
- Perché è il comportamento specificato, non un bug. UUIDv3 e v5 sono identificatori deterministici basati su nome: RFC 9562 afferma che UUID generati dallo stesso nome in forma canonica all'interno dello stesso namespace devono essere uguali. Sono "stesso input, stesso ID" — non assegnazione di ID freschi. Se serve un nuovo ID ogni volta, usa UUIDv4 basato su casualità o UUIDv7 basato sul tempo, e se usi le versioni basate su nome, progetta esplicitamente namespace e canonicalizzazione dei nomi.
- Dovrei comunque aggiungere un vincolo UNIQUE se uso UUID come chiavi?
- Sì. RFC 9562 stesso dice che, sebbene gli UUID forniscano un'unicità sufficiente in pratica, l'unicità globale vera non può mai essere garantita assolutamente, e che gli usi in cui una collisione ha alto impatto dovrebbero adottare contromisure più forti. La baseline pratica è usare gli UUID come ID che difficilmente collidono, mantenere UNIQUE o PRIMARY KEY nel database come ultima linea di difesa, e progettare retry, idempotenza e logging incident per il caso di duplicato. Usare UUID e omettere i vincoli di unicità non sono la stessa cosa.
Profilo dell’autore
Pagina di presentazione dell’autore dell’articolo.
Go Komura
Rappresentante di KomuraSoft LLC
Specializzato nello sviluppo di software Windows, nella consulenza tecnica e nell’analisi dei malfunzionamenti, soprattutto nei progetti con sistemi esistenti e guasti difficili da riprodurre.