CUID2 Generator
Generate secure next-generation CUID2 identifiers
Genererade CUID2s
Vad är CUID2?
CUID2 är den andra generationen av CUID, skriven om från grunden med fokus på kryptografisk säkerhet och integritet.
Till skillnad från CUID v1 som synligt bäddar in tidsstämpeln, döljer CUID2 alla komponenter i en SHA3-hash och skapar praktiskt taget oförutsägbara strängar.
ID:n börjar med ett anpassningsbart alfabetiskt prefix (standard c) följt av en base36-sträng av SHA3-hashen.
Varför CUID2?
CUID2 kom som svar på specifika säkerhetsproblem i CUID v1:
- Exponerad tidsstämpel: CUID v1 avslöjade skapandetiden i början av varje ID.
- Förutsägbarhet: Med kunskap om CUID v1-strukturen kunde en del av det interna tillståndet härledas.
- Brist på kryptografisk säkerhet: CUID v1 använde inte explicit en kryptografiskt säker slumptalsgenerator.
CUID2 åtgärdar dessa problem genom att använda SHA3, CSPRNG och dölja tidsstämpeln.
Designprinciper
CUID2 vs CUID v1
Jämförelse av nyckelkarakteristika mellan de två generationerna:
| Attribut | CUID2 | CUID v1 |
|---|---|---|
| Säkerhet | Kryptografisk (SHA3+CSPRNG) | Icke-kryptografisk |
| Förutsägbarhet | Mycket låg | Låg (exponerad tidsstämpel) |
| Längd | Anpassningsbar (standard 24) | Fast 25 tecken |
| Prefix | Anpassningsbart | Fast 'c' |
| Distribution | Jämnt fördelad | Tidsstämpelpartisk |
| Status | Aktiv och rekommenderad | Inaktuell |
CUID2 vs UUID v4
Jämförelse med den vanliga UUID-standarden:
| Attribut | CUID2 | UUID v4 |
|---|---|---|
| Standardlängd | 24 tecken | 36 tecken |
| URL-säker | Ja | Ja (med bindestreck) |
| Anpassad längd | Ja | Nej |
| Sorterbar | Nej | Nej |
| Entropi | Hög (SHA3) | Hög (CSPRNG) |
| Teckenuppsättning | Alfanumeriska gemener | Hex + bindestreck |
CUID2 erbjuder garanterat alfabetiskt prefix och flexibel längd med säkerhet likvärdig UUID v4.
Vem använder CUID2?
CUID2 har antagits av framstående communities och ramverk:
- Prisma stöder CUID2 som ID-typ i fältet
@idvia@default(cuid()). - Drizzle ORM-communityn antar CUID2 för standard-ID:n.
- SvelteKit- och Remix-projekt använder det för sessions-ID:n.
- Högvolym-API-servrar som behöver spårbara ID:n i loggar.
- Applikationer som synkroniserar över flera databaser eller regioner.
Kodexempel
Installation och användning: pnpm add @paralleldrive/cuid2
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"Avancerad konfiguration:
model User {
id String @id @default(cuid())
email String @unique
name String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}Databasintegration:
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"