Generator UUID v2
Generuje UUID v2 DCE Security z lokalną domeną i ID
Czym jest UUID v2?
UUID v2 to wersja UUID DCE Security, standaryzowana jako część specyfikacji Distributed Computing Environment (DCE) i wymieniona w RFC 4122. Rozszerza UUID v1, osadzając identyfikator użytkownika lub grupy POSIX (UID/GID) w polu znacznika czasu.
Struktura jest podobna do UUID v1, ale 32-bitowe pole time_low jest zastąpione 32-bitowym lokalnym identyfikatorem (np. UID POSIX), a 1-bajtowe pole local_domain identyfikuje rodzaj lokalnego identyfikatora. Znacznik czasu jest w rezultacie skrócony, zmniejszając jego precyzję i gwarancje unikalności.
UUID v2 jest niezwykle rzadki we współczesnym oprogramowaniu. Większość deweloperów nigdy nie będzie musiała go generować. Ta strona dokumentuje format dla kompletności i w celu pomocy w dekodowaniu wartości UUID v2 napotkanych w starszych systemach.
Struktura UUID v2
UUID v2 ma ten sam 128-bitowy format z myślnikami jak inne wersje UUID. Pola różnią się od UUID v1 w następujący sposób:
| Pole | Bity | Cel |
|---|---|---|
| local_id | 32 | <code>local_id</code> — 32-bitowy identyfikator lokalnej domeny (np. UID POSIX z <code>/etc/passwd</code>), zastępuje pole time_low UUID v1 |
| time_mid | 16 | <code>time_mid</code> — środkowe 16 bitów skróconego znacznika czasu UUID v1 |
| time_hi+version | 16 | <code>time_hi_and_version</code> — górne 12 bitów znacznika czasu z nibble wersji ustawionym na <code>2</code> |
| variant+clock_hi | 8 | <code>clock_seq_hi_and_reserved</code> — bity wariantu plus wysoka część sekwencji zegarowej |
| local_domain | 8 | <code>local_domain</code> — identyfikator domeny: <code>0</code> = Użytkownik POSIX (UID), <code>1</code> = Grupa POSIX (GID), <code>2</code> = Organizacja |
| node | 48 | <code>node</code> — 48-bitowy adres MAC generującego hosta |
Przykład: 000003e8-92e0-21ef-8000-325096b39f47 — local_id 0x000003e8 = UID 1000, local_domain 0x00 = Użytkownik POSIX
Wartości lokalnej domeny
Bajt local_domain określa typ lokalnego identyfikatora osadzonego w UUID:
Wartości domeny są zdefiniowane przez specyfikację DCE. Wartości 3–255 są zarezerwowane. W praktyce tylko domena 0 (Osoba/UID) jest powszechnie spotykana w rzeczywistych wartościach UUID v2.
Dlaczego UUID v2 jest rzadko używany
Trzy cechy sprawiają, że UUID v2 jest niepraktyczny dla większości nowoczesnych aplikacji:
Niska rozdzielczość znacznika czasu
Znacznik czasu jest skrócony do 28 bitów (ziarnistość około 7,2 minuty). W tym oknie UUID generowane z tym samym local_id i domeną na tym samym hoście nie są unikalne — specyfikacja polega na polu clock_seq, aby je różnicować, ograniczając unikalność do 64 wartości na okno 7-minutowe.
Brak obsługi przez standardowe biblioteki
W przeciwieństwie do UUID v1 i v4, UUID v2 nie jest obsługiwany przez większość bibliotek UUID. Pakiet npm uuid, moduł uuid Pythona i java.util.UUID Javy pomijają v2. Wymagana jest niestandardowa implementacja.
Semantyka specyficzna dla POSIX
Koncepcja lokalnej domeny (UID/GID) jest z natury specyficzna dla POSIX i nie przekłada się sensownie na Windows, systemy wbudowane ani środowiska chmurowe, w których koncepcja identyfikatora użytkownika POSIX jest nieobecna.
Kontekst historyczny
UUID v2 został zdefiniowany jako część Distributed Computing Environment (DCE/RPC) Open Software Foundation na początku lat 90. Celem było tworzenie UUID, które mogłyby przenosić kontekst autoryzacji — konkretnie, aby serwer RPC mógł zidentyfikować wywołującego użytkownika bez osobnego kroku uwierzytelniania.
Model bezpieczeństwa DCE zakładał jednorodne środowisko POSIX, w którym każdy węzeł uczestniczył w wspólnej przestrzeni nazw UID/GID. Osadzony UID pozwalałby serwerowi szybko sprawdzać listy kontroli dostępu bez konieczności odpytywania usługi katalogowej.
- Internet przeszedł od jednorodnych środowisk POSIX w kierunku heterogenicznych architektur chmurowych
- Nowoczesne uwierzytelnianie używa tokenów (JWT, OAuth) zamiast osadzonych UID w identyfikatorach
- UUID v4 (w pełni losowy) i UUID v7 (posortowany według czasu) pokrywają praktyczne przypadki użycia dla unikalnych identyfikatorów
- DCE/RPC sam w sobie wyszedł z powszechnego użycia
RFC 4122 (2005) zawierał UUID v2 przez odwołanie do specyfikacji DCE, ale celowo pominął szczegółowy algorytm generowania — zauważając, że jest on zdefiniowany przez DCE, a nie IETF.
RFC 9562 (2024), który zaktualizował standard UUID, zachował UUID v2 dla historycznej kompletności, ale nadal zwracał uwagę na jego specyficzną dla POSIX naturę i brak kompletnego algorytmu generowania w standardzie IETF.
UUID v2 a UUID v1
UUID v2 pochodzi z UUID v1. Oto porównanie:
| Aspekt | UUID v1 | UUID v2 |
|---|---|---|
| Bity znacznika czasu | 60 bitów (~precyzja 100ns) | 28 bitów (~precyzja 7,2 minuty) |
| Lokalny identyfikator | Brak | 32-bitowy POSIX UID/GID |
| Lokalna domena | Nie obecna | 0=UID, 1=GID, 2=Org |
| Pole węzła | Adres MAC | Adres MAC |
| Obsługa przez biblioteki | Szeroko obsługiwany | Rzadko obsługiwany |
| Standard | RFC 4122 / RFC 9562 | Specyfikacja DCE (wymieniona przez RFC 4122) |
| Praktyczne użycie | Starsze identyfikatory posortowane według czasu (Cassandra) | Wyłącznie konteksty DCE Security |
UUID v2 nie oferuje nic więcej niż UUID v1 do ogólnego użytku i jest ściśle gorszy pod większością względów. Nie ma powodu, aby wybierać UUID v2 dla nowego rozwoju.
Przykłady kodu
UUID v2 nie ma natywnej obsługi w standardowych bibliotekach. Poniższe przykłady pokazują, jak pracować z wartościami UUID v2:
Python — ręczna implementacja
import uuid, struct, time
def uuid_v2(local_id: int, local_domain: int = 0) -> str:
"""
Generate a DCE Security UUID (v2).
local_domain: 0 = POSIX UID, 1 = POSIX GID, 2 = Org
local_id: 32-bit unsigned integer (e.g. os.getuid())
"""
# Get a v1 UUID for the time and node fields
v1 = uuid.uuid1()
fields = list(v1.fields) # [time_low, time_mid, time_hi_version, clock_seq_hi_variant, clock_seq_low, node]
# Replace time_low with local_id
fields[0] = local_id & 0xFFFFFFFF
# Replace version nibble: clear lower 12 bits of time_hi, set version 2
fields[2] = (fields[2] & 0x0FFF) | 0x2000
# Replace clock_seq_low with local_domain
fields[4] = local_domain & 0xFF
return str(uuid.UUID(fields=tuple(fields)))
import os
print(uuid_v2(os.getuid(), local_domain=0)) # POSIX UID
print(uuid_v2(os.getgid(), local_domain=1)) # POSIX GID
Go — uwaga
// The standard "github.com/google/uuid" package does NOT support v2. // You would need to implement it manually, similar to the Python example above. // Most Go developers use v4 or v7 for new projects. import "github.com/google/uuid" v4 := uuid.New() // v4 — recommended for most use cases v7, _ := uuid.NewV7() // v7 — time-ordered, ideal for database primary keys
JavaScript — wyodrębnij pola
Aby wyodrębnić local_id i domenę z istniejącego ciągu UUID v2:
// Extracting fields from a UUID v2 string
const uuidStr = '000003e8-1234-2abc-8200-a1b2c3d4e5f6'
// ^^^^^^^^ ^^^^ ^ ^^
// local_id ver variant+clockSeqHi
// ^^ = local_domain (00 = POSIX UID)
const parts = uuidStr.split('-')
const localId = parseInt(parts[0], 16) // → 1000 (0x3e8)
const version = parseInt(parts[2][0], 16) // → 2
const localDomain = parseInt(parts[3].slice(2), 16) // low byte of octet pair
const DOMAIN_NAMES = ['POSIX UID', 'POSIX GID', 'Org']
console.log(`Local ID: ${localId}`) // Local ID: 1000
console.log(`Version: ${version}`) // Version: 2
console.log(`Domain: ${DOMAIN_NAMES[localDomain]}`) // Domain: POSIX UID
google/uuid obsługuje generowanie UUID v2 przez uuid.NewDCEGroup() i uuid.NewDCEPerson() — jedna z niewielu popularnych bibliotek, które to robią.