CUID2 Generator
Generate secure next-generation CUID2 identifiers
Gegenereerde CUID2s
Wat is CUID2?
CUID2 (Collision-resistant Unique ID, versie 2) is de volgende-generatie opvolger van CUID v1, ontworpen om korte, cryptografisch veilige, ondoorzichtige ID's te genereren die veilig zijn om te gebruiken als primaire sleutels in databases, URL's en gedistribueerde systemen.
In tegenstelling tot zijn voorganger onthult CUID2 geen informatie over het tijdstip van aanmaak, de hostmachine of het proces dat het heeft gegenereerd. Elk ID is een schijnbaar willekeurige string die begint met een willekeurige kleine letter gevolgd door een base-36 hash afgeleid van SHA-512. De standaardlengte is 24 tekens, maar u kunt het configureren van 2 tot 32 tekens.
CUID2 wordt sterk aanbevolen door moderne databasetoolkits. Prisma heeft het aangenomen als de standaard ID-strategie voor zijn @default(cuid()) scalair, en PlanetScale, Neon en andere serverloze databaseproviders vermelden CUID2 expliciet als een voorkeursformaat.
Waarom CUID2 CUID v1 Verving
CUID v1, uitgebracht in 2012 door Eric Elliott, was een belangrijke verbetering ten opzichte van gewone UUID's voor ID-generatie aan de clientzijde. Beveiligingsonderzoekers ontdekten echter twee fundamentele problemen met het ontwerp:
- Vingerafdruk: De hostvingerafdruk ingebed in elke CUID v1-waarde kon worden gebruikt om de machine of het proces te identificeren dat het ID heeft gegenereerd, waardoor operationele metadata werden gelekt aan iedereen die de ID's kon observeren.
- Voorspelbaarheid: Omdat CUID v1 een monotoon stijgende teller en een tijdstempelsegment bevatte, kon een aanvaller die meerdere ID's observeerde het approximate bereik van toekomstige ID's voorspellen, wat enumeratieaanvallen op API's mogelijk maakte die ID's als de enige autorisatiecontrole gebruiken.
- Niet-cryptografische hash: CUID v1 gebruikte een eenvoudige niet-cryptografische hashstap die niet voldeed aan moderne beveiligingsstandaarden.
Eric Elliott, de oorspronkelijke auteur, verklaarde CUID v1 formeel als verouderd en schreef CUID2 van scratch om al deze problemen op te lossen. Het nieuwe algoritme gebruikt de Web Crypto API (SHA-512) en elimineert alle deterministische componenten.
CUID2 Ontwerpprincipes
CUID2 vs CUID v1 — Vergelijking
De onderstaande tabel geeft een overzicht van de belangrijkste verschillen tussen CUID2 en het nu verouderde CUID v1. Als u momenteel CUID v1 gebruikt, wordt migratie naar CUID2 sterk aanbevolen.
| Attribuut | CUID2 | CUID v1 |
|---|---|---|
| Beveiliging | Cryptografisch (SHA-512) | Niet-cryptografisch (vingerafdruk-gebaseerd) |
| Voorspelbaarheid | Ondoorzichtig — geen metadata gelekt | Tijdstempel + vingerafdruk zichtbaar in ID |
| Lengte | Configureerbaar (2–32 tekens) | Vast 25 tekens |
| Voorvoegsel | Willekeurige letter a–z | Begint altijd met "c" |
| Verdeling | Vlak / uniform | Monotoon stijgende segmenten |
| Status | Actief onderhouden | Verouderd door originele auteur |
CUID2 vs UUID v4 — Vergelijking
UUID v4 is de dominante standaard voor willekeurige unieke ID's. CUID2 biedt verschillende praktische voordelen ten opzichte van UUID v4 zonder beveiliging op te offeren.
| Attribuut | CUID2 | UUID v4 |
|---|---|---|
| Standaardlengte | 24 tekens | 36 tekens (met koppeltekens) |
| URL-veilig | Ja — kleine letters a–z + 0–9 | Vereist codering (bevat koppeltekens) |
| Aangepaste lengte | Ja (2–32) | Nee — altijd 128 bits / 36 tekens |
| Sorteerbaar | Nee (by design) | Nee (v4 is willekeurig) |
| Entropiebron | SHA-512 + Web Crypto | CSPRNG |
| Tekenset | Base-36 (a–z, 0–9) | Hex + koppeltekens |
De belangrijkste afweging is bekendheid: UUID v4 is een IETF-standaard (RFC 4122) die door vrijwel elke database, programmeertaal en API-framework wordt herkend. CUID2 is een communitystandaard met groeiende maar niet universele ondersteuning. Kies UUID v4 wanneer interoperabiliteit met externe systemen van het grootste belang is; kies CUID2 wanneer u beide uiteinden beheert en de voorkeur geeft aan kortere, URL-veilige ID's.
Wie Gebruikt CUID2
CUID2 heeft snelle adoptie gezien in het moderne JavaScript- en TypeScript-ecosysteem:
- Prisma — de populairste TypeScript ORM gebruikt CUID2 als aanbevolen standaard voor
@id-velden met@default(cuid())in Prisma Schema v2+. - PlanetScale — hun documentatie en startersjablonen bevelen CUID2 aan voor door applicaties gegenereerde primaire sleutels om problemen met sequentieel scannen op hun gedistribueerde MySQL-platform te vermijden.
- Drizzle ORM — biedt een ingebouwde standaard-helper
cuid2()voor kolomdefinities. - tRPC-boilerplates — veel community tRPC + Prisma-startersjablonen worden geleverd met CUID2 als primaire sleutelstrategie.
- T3 Stack — het create-t3-app-scaffoldingtool gebruikt Prisma met CUID2-standaarden in gegenereerde schemabestanden.
Codevoorbeelden
Het officiële npm-pakket @paralleldrive/cuid2 biedt een eenvoudige API:
import { createId } from '@paralleldrive/cuid2'
// Generate a single CUID2 (default length: 24)
const id = createId()
console.log(id) // e.g. "tz4a98xxat96iws9zmbrgj3a"
// Custom length
import { init } from '@paralleldrive/cuid2'
const createShortId = init({ length: 16 })
const shortId = createShortId()
console.log(shortId) // e.g. "tz4a98xxat96iws9"CUID2 gebruiken met Prisma-schema:
model User {
id String @id @default(cuid())
email String @unique
name String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}CUID2 genereren in Node.js zonder het npm-pakket (alleen Web Crypto API gebruiken, zoals dit hulpmiddel in de browser doet):
async function generateCuid2(length = 24) {
const alphabet = 'abcdefghijklmnopqrstuvwxyz'
// Random prefix letter
const firstByte = crypto.getRandomValues(new Uint8Array(1))[0]
const firstChar = alphabet[firstByte % 26]
// Random 32-byte salt
const salt = crypto.getRandomValues(new Uint8Array(32))
const saltHex = [...salt].map(b => b.toString(16).padStart(2, '0')).join('')
// SHA-512 of timestamp + salt
const input = Date.now().toString(36) + saltHex
const hashBuffer = await crypto.subtle.digest(
'SHA-512',
new TextEncoder().encode(input)
)
// Encode hash bytes as base-36 string
const bytes = new Uint8Array(hashBuffer)
let hash = ''
for (let i = 0; i < bytes.length; i += 8) {
let chunk = 0n
for (let j = 0; j < 8 && i + j < bytes.length; j++) {
chunk = (chunk << 8n) | BigInt(bytes[i + j])
}
hash += chunk.toString(36)
}
return (firstChar + hash).slice(0, length)
}
// Usage
const id = await generateCuid2()
console.log(id) // e.g. "m7k3r9p2nxq8zt5a6cwj4bvd"