เครื่องสร้าง CUID2
สร้าง identifier CUID2 รุ่นใหม่ที่ปลอดภัย
CUID2 ที่สร้างแล้ว
CUID2 คืออะไร?
CUID2 คือรุ่นที่สองของ CUID เขียนใหม่ตั้งแต่ต้นโดยมุ่งเน้นที่ความปลอดภัยทางการเข้ารหัสและความเป็นส่วนตัว
ต่างจาก CUID v1 ที่ฝัง timestamp อย่างมองเห็นได้ CUID2 ซ่อนทุกส่วนประกอบไว้ใน hash SHA3 สร้าง string ที่ไม่สามารถคาดเดาได้ในทางปฏิบัติ
ID เริ่มต้นด้วย prefix ตัวอักษรที่ปรับแต่งได้ (ค่าเริ่มต้น c) ตามด้วย base36 string ของ hash SHA3
ทำไมต้องใช้ CUID2?
CUID2 เกิดขึ้นเพื่อตอบสนองต่อข้อกังวลด้านความปลอดภัยเฉพาะใน CUID v1:
- Timestamp ที่เปิดเผย: CUID v1 เปิดเผยเวลาสร้างที่จุดเริ่มต้นของ ID แต่ละตัว
- ความสามารถในการคาดเดา: ด้วยความรู้เกี่ยวกับโครงสร้าง CUID v1 สามารถอนุมาน state ภายในบางส่วนได้
- ขาดความปลอดภัยทางการเข้ารหัส: CUID v1 ไม่ได้ใช้ตัวสร้างตัวเลขสุ่มที่ปลอดภัยทางการเข้ารหัสอย่างชัดเจน
CUID2 แก้ไขข้อกังวลเหล่านี้โดยใช้ SHA3, CSPRNG และการซ่อน timestamp
หลักการออกแบบ
CUID2 เทียบกับ CUID v1
เปรียบเทียบคุณลักษณะสำคัญระหว่างสองรุ่น:
| คุณลักษณะ | CUID2 | CUID v1 |
|---|---|---|
| ความปลอดภัย | ทางการเข้ารหัส (SHA3+CSPRNG) | ไม่ใช่การเข้ารหัส |
| ความสามารถในการคาดเดา | ต่ำมาก | ต่ำ (timestamp เปิดเผย) |
| ความยาว | ปรับแต่งได้ (ค่าเริ่มต้น 24) | คงที่ 25 ตัวอักขระ |
| Prefix | ปรับแต่งได้ | คงที่ 'c' |
| การกระจาย | กระจายอย่างสม่ำเสมอ | เอนเอียงตาม timestamp |
| สถานะ | ใช้งานอยู่ & แนะนำ | เลิกใช้แล้ว |
CUID2 เทียบกับ UUID v4
เปรียบเทียบกับมาตรฐาน UUID ที่ใช้กันทั่วไป:
| คุณลักษณะ | CUID2 | UUID v4 |
|---|---|---|
| ความยาวค่าเริ่มต้น | 24 ตัวอักขระ | 36 ตัวอักขระ |
| ปลอดภัยสำหรับ URL | ใช่ | ใช่ (พร้อม hyphen) |
| ความยาวกำหนดเอง | ใช่ | ไม่ |
| เรียงลำดับได้ | ไม่ | ไม่ |
| Entropy | สูง (SHA3) | สูง (CSPRNG) |
| ชุดอักขระ | ตัวอักษรตัวเล็กและตัวเลข | Hex + hyphen |
CUID2 ให้ prefix ตัวอักษรที่รับประกันและความยาวที่ยืดหยุ่นพร้อมความปลอดภัยเทียบเท่า UUID v4
ใครใช้ CUID2?
CUID2 ถูกนำมาใช้โดยชุมชนและ framework ที่มีชื่อเสียง:
- Prisma รองรับ CUID2 เป็นประเภท ID ในฟิลด์
@idผ่าน@default(cuid()) - ชุมชน Drizzle ORM นำ CUID2 มาใช้สำหรับ ID เริ่มต้น
- โปรเจกต์ SvelteKit และ Remix ใช้มันสำหรับ session ID
- API server ปริมาณสูงที่ต้องการ ID ที่ติดตามได้ใน log
- แอปพลิเคชันที่ซิงโครไนซ์ในหลายฐานข้อมูลหรือภูมิภาค
ตัวอย่างโค้ด
การติดตั้งและการใช้งาน: 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"การกำหนดค่าขั้นสูง:
model User {
id String @id @default(cuid())
email String @unique
name String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}การรวมฐานข้อมูล:
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"