Générateur CUID2
Génère des identifiants CUID2 sécurisés de nouvelle génération
CUID2s générés
Qu'est-ce que CUID2 ?
CUID2 (Collision-resistant Unique ID, version 2) est le successeur de nouvelle génération de CUID v1, conçu pour générer des identifiants courts, cryptographiquement sécurisés et opaques qui sont sûrs à utiliser comme clés primaires dans les bases de données, les URL et les systèmes distribués.
Contrairement à son prédécesseur, CUID2 ne révèle aucune information sur le moment de création, la machine hôte ou le processus qui l'a généré. Chaque identifiant est une chaîne apparemment aléatoire qui commence par une lettre minuscule aléatoire suivie d'un hash base-36 dérivé de SHA-512. La longueur par défaut est de 24 caractères, mais vous pouvez la configurer de 2 à 32 caractères selon vos contraintes de stockage.
CUID2 est largement recommandé par les kits d'outils de bases de données modernes. Prisma l'a adopté comme stratégie d'identifiant par défaut pour son scalaire @default(cuid()), et PlanetScale, Neon et d'autres fournisseurs de bases de données serverless listent explicitement CUID2 comme format d'identifiant préféré car il évite les vulnérabilités de scan séquentiel des entiers auto-incrémentés tout en étant plus court et plus lisible qu'un UUID.
Pourquoi CUID2 a Remplacé CUID v1
CUID v1, sorti en 2012 par Eric Elliott, était une amélioration majeure par rapport aux UUID simples pour la génération d'identifiants côté client. Cependant, des chercheurs en sécurité ont découvert deux problèmes fondamentaux avec sa conception :
- Fingerprinting : L'empreinte d'hôte intégrée dans chaque valeur CUID v1 pouvait être utilisée pour identifier la machine ou le processus qui a généré l'identifiant, révélant des métadonnées opérationnelles à toute personne pouvant observer les identifiants.
- Prévisibilité : Comme CUID v1 incorporait un compteur monotoniquement croissant et un segment d'horodatage, un attaquant observant plusieurs identifiants pouvait prédire la plage approximative des futurs identifiants, permettant des attaques d'énumération contre des API utilisant les identifiants comme seul contrôle d'autorisation.
- Hash non cryptographique : CUID v1 utilisait une étape de hash non cryptographique simple qui ne répondait pas aux normes de sécurité modernes.
Eric Elliott, l'auteur original, a formellement déprécié CUID v1 et créé CUID2 de zéro pour résoudre tous ces problèmes. Le nouvel algorithme utilise la Web Crypto API (SHA-512) et élimine tous les composants déterministes, rendant chaque identifiant statistiquement indépendant de tous les autres.
Principes de Conception de CUID2
CUID2 vs CUID v1 — Comparaison
Le tableau ci-dessous résume les différences clés entre CUID2 et le maintenant obsolète CUID v1. Si vous utilisez actuellement CUID v1, la migration vers CUID2 est fortement recommandée.
| Attribut | CUID2 | CUID v1 |
|---|---|---|
| Sécurité | Cryptographique (SHA-512) | Non cryptographique (basé sur empreinte) |
| Prévisibilité | Opaque — aucune métadonnée divulguée | Horodatage + empreinte visible dans l'identifiant |
| Longueur | Configurable (2–32 chars) | Fixe 25 chars |
| Préfixe | Lettre aléatoire a–z | Commence toujours par "c" |
| Distribution | Plate / uniforme | Segments monotoniquement croissants |
| Statut | Activement maintenu | Déprécié par l'auteur original |
CUID2 vs UUID v4 — Comparaison
UUID v4 est le standard dominant pour les identifiants uniques aléatoires. CUID2 offre plusieurs avantages pratiques sur UUID v4 sans sacrifier la sécurité.
| Attribut | CUID2 | UUID v4 |
|---|---|---|
| Longueur par défaut | 24 caractères | 36 caractères (avec tirets) |
| Sûr pour URL | Oui — minuscules a–z + 0–9 | Nécessite un encodage (contient des tirets) |
| Longueur personnalisée | Oui (2–32) | Non — toujours 128 bits / 36 chars |
| Triable | Non (par conception) | Non (v4 est aléatoire) |
| Source d'entropie | SHA-512 + Web Crypto | CSPRNG |
| Jeu de caractères | Base-36 (a–z, 0–9) | Hex + tirets |
Le principal compromis est la familiarité : UUID v4 est un standard IETF (RFC 4122) reconnu par pratiquement toutes les bases de données, langages de programmation et frameworks d'API. CUID2 est un standard communautaire avec un support croissant mais pas universel. Choisissez UUID v4 lorsque l'interopérabilité avec des systèmes externes est primordiale ; choisissez CUID2 lorsque vous contrôlez les deux extrémités et préférez des identifiants plus courts et sûrs pour les URL.
Qui Utilise CUID2
CUID2 a connu une adoption rapide dans l'écosystème moderne JavaScript et TypeScript :
- Prisma — l'ORM TypeScript le plus populaire utilise CUID2 comme défaut recommandé pour les champs
@idavec@default(cuid())dans Prisma Schema v2+. - PlanetScale — leur documentation et modèles de démarrage recommandent CUID2 pour les clés primaires générées par l'application afin d'éviter les problèmes de performance de scan séquentiel sur leur plateforme MySQL distribuée.
- Drizzle ORM — fournit un helper par défaut intégré
cuid2()pour les définitions de colonnes. - Modèles tRPC — de nombreux modèles communautaires tRPC + Prisma sont livrés avec CUID2 comme stratégie de clé primaire.
- T3 Stack — l'outil de scaffolding create-t3-app utilise Prisma avec des valeurs par défaut CUID2 dans les fichiers de schéma générés.
Exemples de Code
Le package npm officiel @paralleldrive/cuid2 fournit une API simple :
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"Utilisation de CUID2 avec le schéma Prisma :
model User {
id String @id @default(cuid())
email String @unique
name String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}Génération de CUID2 dans Node.js sans le package npm (en utilisant uniquement la Web Crypto API, comme le fait cet outil dans le navigateur) :
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"