Trình tạo UUID v4

Tạo UUID v4 ngẫu nhiên an toàn về mặt mật mã

Định dạng

Số lượng:

UUID v4 là phiên bản UUID được triển khai rộng rãi nhất trong phần mềm hiện đại. Không giống các phiên bản khác lấy bit từ timestamp hoặc hash namespace, UUID v4 được xây dựng hoàn toàn từ dữ liệu ngẫu nhiên — làm cho nó trở thành lựa chọn đơn giản và di động nhất khi bạn cần một định danh duy nhất không mang metadata về nguồn gốc.

Bộ tạo này sử dụng crypto.randomUUID(), API trình duyệt và Node.js gốc, lấy entropy từ bộ tạo số ngẫu nhiên an toàn về mặt mật mã của hệ điều hành — cùng nguồn được dùng cho khóa TLS.

UUID v4 là gì?

Universally Unique Identifier (UUID) là nhãn 128-bit được chuẩn hóa trong RFC 4122. Nó thường được biểu diễn dưới dạng 32 chữ số thập lục phân được nhóm bằng dấu gạch nối theo mẫu 8-4-4-4-12:

550e8400-e29b-41d4-a716-446655440000

Trong UUID v4, 122 trong 128 bit là ngẫu nhiên. 6 bit còn lại là các trường cố định được quy định bởi spec: 4 bit mã hóa phiên bản (0100 = 4) và 2 bit mã hóa biến thể RFC 4122 (10). Đó là lý do nhóm thứ ba luôn bắt đầu bằng 4 và nhóm thứ tư luôn bắt đầu bằng 8, 9, a, hoặc b.

Cấu trúc UUID v4

Phân tích 550e8400-e29b-41d4-a716-446655440000:

Phân đoạnBitÝ nghĩa
550e840032 ngẫu nhiêntime_low (tên lịch sử — hoàn toàn ngẫu nhiên trong v4)
e29b16 ngẫu nhiêntime_mid (tên lịch sử — hoàn toàn ngẫu nhiên trong v4)
41d44 cố định + 12 ngẫu nhiênNibble phiên bản 4 (nhị phân 0100) + 12 bit ngẫu nhiên
a7162 cố định + 14 ngẫu nhiênBit biến thể 10 (MSB của byte đầu tiên) + 14 bit ngẫu nhiên
44665544000048 ngẫu nhiênnode (hoàn toàn ngẫu nhiên trong v4)
Note:Nibble biến thể ở đầu nhóm thứ tư luôn là một trong 8, 9, a, hoặc b — vì hai bit cao của byte đó được cố định thành 10 (dấu biến thể RFC 4122), để hai bit còn lại tự do thay đổi.

UUID v4 so với các Phiên bản khác

RFC 4122 định nghĩa năm phiên bản UUID. Mỗi phiên bản giải quyết một vấn đề khác nhau:

UUID v1Timestamp + MAC

Kết hợp timestamp 60-bit (khoảng 100 nanosecond từ tháng 10 năm 1582) với địa chỉ MAC của máy chủ. Tăng đơn điệu trong một máy.

Use when: khi bạn cần ID theo thứ tự thời gian và không ngại lộ danh tính máy chủ.

UUID v3Hash MD5

Xác định: cùng namespace + tên luôn tạo ra cùng UUID. Sử dụng hashing MD5.

Use when: khi bạn cần ID có thể tái tạo từ namespace đã biết. Ưu tiên v5 hơn v3.

UUID v4Ngẫu nhiên

122 bit ngẫu nhiên an toàn về mặt mật mã. Không timestamp, không MAC, không namespace.

Use when: khi bạn cần ID duy nhất không có ý nghĩa cấu trúc và bảo mật tối đa.

UUID v5Hash SHA-1

Giống v3 nhưng sử dụng SHA-1. Vẫn xác định từ namespace + tên.

Use when: khi bạn cần định danh có thể tái tạo, dựa trên nội dung.

UUID v7Ngẫu nhiên theo thứ tự thời gian

Mới hơn (RFC 9562, 2024). Mã hóa timestamp Unix mili giây ở bit cao, sau đó là bit ngẫu nhiên. Có thể sắp xếp và thân thiện với database.

Use when: khi bạn cần ID thân thiện với chỉ mục database với thứ tự thời gian tự nhiên.

Khi nào nên dùng UUID v4

UUID v4 là công cụ phù hợp trong phần lớn các tình huống khi bạn chỉ cần "một ID duy nhất":

ID người dùng và tài khoản

ID người dùng không rõ ràng không tiết lộ gì về thời gian tạo tài khoản hoặc danh tính máy chủ.

Khóa chính database

Hoạt động với bất kỳ database engine nào. UUID v4 an toàn để tạo ở phía client và hợp nhất từ các nguồn phân tán.

ID phiên và token

122 bit ngẫu nhiên làm cho việc đoán brute-force không khả thi về mặt tính toán.

Tên file và đối tượng

Tên file an toàn để loại trùng lặp cho uploads, khóa đối tượng S3, hoặc các mục cache.

Khóa idempotency

Tạo UUID ở client trước khi gửi yêu cầu. Server có thể loại bỏ trùng lặp các yêu cầu thử lại một cách an toàn.

ID tương quan và theo dõi

Gắn UUID vào mỗi dòng log và span theo dõi phân tán.

Note:Nếu trường hợp sử dụng của bạn yêu cầu ID có thể sắp xếp (ví dụ: bạn muốn các hàng database được nhóm theo thời gian chèn), hãy xem xét dùng UUID v7 thay thế. UUID v4 hoàn toàn ngẫu nhiên và sẽ gây phân mảnh chỉ mục trong chỉ mục B-tree khi tốc độ chèn cao.

Xác suất Va chạm

Với 122 bit ngẫu nhiên, không gian UUID v4 chứa 2122 ≈ 5,3 × 1036 giá trị có thể. Xác suất va chạm tuân theo bài toán sinh nhật:

UUID được tạoXác suất va chạm
1 tỷ (109)~1 trong 5,3 × 1018
1 nghìn tỷ (1012)~1 trong 5,3 × 1012
1018 (1 exabyte)~1 trong 5.300

Để có 50% cơ hội va chạm, bạn cần tạo khoảng 2,71 × 1018 UUID. Ở tốc độ 1 tỷ UUID mỗi giây, sẽ mất khoảng 85 năm tạo liên tục.

Ví dụ Mã

JavaScript — Trình duyệt và Node.js 14.17+

Phương thức crypto.randomUUID() có sẵn nguyên bản trong tất cả các trình duyệt hiện đại và Node.js 14.17+. Không cần cài đặt gói.

js
// Browser or Node.js 14.17+
const id = crypto.randomUUID()
// → "110e8400-e29b-41d4-a716-446655440000"

// Generate multiple
const ids = Array.from({ length: 5 }, () => crypto.randomUUID())

Node.js — phiên bản cũ hơn (gói uuid)

js
const { v4: uuidv4 } = require('uuid')

const id = uuidv4()
// → "110e8400-e29b-41d4-a716-446655440000"

Python

python
import uuid

# Generate a UUID v4
id = str(uuid.uuid4())
# → '110e8400-e29b-41d4-a716-446655440000'

# The uuid module uses os.urandom() — cryptographically secure
print(uuid.uuid4().hex)  # without hyphens
# → '110e8400e29b41d4a716446655440000'

Go

go
import "github.com/google/uuid"

id := uuid.New().String()
// → "110e8400-e29b-41d4-a716-446655440000"

// Or using the standard library (Go 1.20+ with math/rand/v2 is NOT cryptographic)
// Always prefer github.com/google/uuid for production use

Rust

toml
# Cargo.toml
[dependencies]
uuid = { version = "1", features = ["v4"] }
rust
use uuid::Uuid;

let id = Uuid::new_v4().to_string();
// → "110e8400-e29b-41d4-a716-446655440000"

Câu hỏi Thường gặp

UUID v4 có an toàn về mặt mật mã không?

UUID v4 bản thân nó không phải là nguyên thủy bảo mật — đó là định dạng định danh. Tuy nhiên, khi được tạo qua crypto.randomUUID() (trình duyệt hoặc Node.js) hoặc các API tương đương ở cấp hệ điều hành, entropy nền tảng là an toàn về mặt mật mã. Điều này có nghĩa các giá trị UUID v4 phù hợp để dùng làm token phiên hoặc khóa idempotency, khi tính không thể đoán trước là quan trọng. Không dùng các bộ tạo UUID dựa trên Math.random() cho các ngữ cảnh nhạy cảm về bảo mật — chỉ dùng các API rõ ràng lấy từ CSPRNG của hệ điều hành.

Hai UUID v4 có thể bằng nhau không?

Về mặt lý thuyết có, nhưng thực tế không. Xác suất tạo ra một bản trùng trong bất kỳ tập dữ liệu thực tế nào (hàng tỷ ID) là cực kỳ nhỏ — thấp hơn nhiều so với khả năng lỗi phần cứng gây hỏng dữ liệu. Xung đột UUID v4 được coi là không thể xảy ra trong thiết kế hệ thống sản xuất. Nếu bạn thực sự cần đảm bảo không xung đột, hãy dùng bộ đếm tập trung hoặc chuỗi database thay thế.

UUID v4 so với nanoid — nên dùng cái nào?

Cả hai đều là bộ tạo ID ngẫu nhiên được hỗ trợ bởi CSPRNG. Sự khác biệt chính:

  • UUID v4 tuân theo tiêu chuẩn RFC 4122, được nhận dạng bởi mọi database và framework, và không yêu cầu phụ thuộc (native crypto.randomUUID()).
  • nanoid sử dụng bảng chữ cái URL-safe và ngắn hơn theo mặc định (21 ký tự so với 36). Yêu cầu gói npm.

Ưu tiên UUID v4 khi khả năng tương tác với hệ thống bên ngoài quan trọng. Ưu tiên nanoid khi bạn muốn ID ngắn hơn.

Tôi có nên lưu UUID dưới dạng chuỗi hay nhị phân trong database không?

Đối với hầu hết các database, lưu dưới dạng cột UUID hoặc BINARY(16) (16 byte) hiệu quả hơn chuỗi VARCHAR(36) (36 byte). PostgreSQL có kiểu uuid gốc. MySQL và MariaDB hoạt động tốt với BINARY(16) cùng các hàm trợ giúp UUID_TO_BIN() / BIN_TO_UUID(). Người dùng SQLite thường lưu dưới dạng TEXT. Lựa chọn lưu trữ không ảnh hưởng đến tính duy nhất hay tính đúng đắn.

Tại sao UUID v4 có dấu gạch nối — và tôi có thể bỏ qua chúng không?

Dấu gạch nối là một phần của biểu diễn UUID chính tắc được định nghĩa bởi RFC 4122. Chúng hoàn toàn là trang trí — không mang thông tin và không ảnh hưởng đến giá trị 128-bit. Bỏ chúng đi sẽ cho bạn một chuỗi hex 32 ký tự gọn hơn nhưng tương đương về mặt chức năng. Hầu hết các trình phân tích UUID chấp nhận cả hai dạng. Khi không chắc, hãy dùng dạng có dấu gạch nối chính tắc để đảm bảo tương thích tối đa với các công cụ và database bên thứ ba.

js
const id = crypto.randomUUID()              // "550e8400-e29b-41d4-a716-446655440000"
const compact = id.replaceAll('-', '')     // "550e8400e29b41d4a716446655440000"