UUID v3生成器
Generate deterministic name-based UUID v3 using MD5
命名空间
6ba7b810-9dad-11d1-80b4-00c04fd430c8
名称
已生成的 UUID v3
什么是 UUID v3?
UUID v3 是在 RFC 4122 中定义的基于名称的 UUID 版本。它不使用随机数据或时间戳,而是从两个输入中确定性地派生 UUID:一个命名空间 UUID 和一个名称字符串。命名空间 + 名称对使用 MD5 进行哈希,结果哈希被格式化为 UUID。
UUID v3 的关键属性是确定性:相同的命名空间和名称将始终在任何机器、任何时间产生相同的 UUID。这使它适合内容寻址——为由有意义名称标识的资源生成稳定标识符。
UUID v3 使用 MD5 作为其哈希函数。MD5 在安全目的上被认为是加密破解的,这就是为什么通常对新开发优先选择 UUID v5(使用 SHA-1)的原因。v3 和 v5 都不提供任何随机性——它们纯粹是确定性的。
标准命名空间
RFC 4122 定义了四个预分配的命名空间 UUID。使用标准命名空间确保互操作性——两个独立的实现将在同一命名空间内为同一名称生成相同的 UUID v3:
| 命名空间 | UUID | 用于 |
|---|---|---|
| DNS | 6ba7b810-9dad-11d1-80b4-00c04fd430c8 | 完全限定域名(例如 'example.com') |
| URL | 6ba7b811-9dad-11d1-80b4-00c04fd430c8 | URL 和 URI(例如 'https://example.com/resource') |
| OID | 6ba7b812-9dad-11d1-80b4-00c04fd430c8 | ISO 对象标识符(例如 '1.2.840.113556') |
| X.500 | 6ba7b814-9dad-11d1-80b4-00c04fd430c8 | X.500 可分辨名称(例如 'cn=John,dc=example,dc=com') |
你也可以使用任意 UUID 作为自定义命名空间——例如,你生成一次并作为常量嵌入应用程序的 UUID v4。这让你可以为自己的名称到 UUID 映射创建私有命名空间。
UUID v3 vs UUID v5
UUID v3 和 UUID v5 在结构上完全相同——两者都是确定性的、基于名称的 UUID。唯一的区别是哈希函数:
- 使用 MD5 哈希
- 128 位输出(UUID 大小)
- 在 RFC 4122 中定义
- MD5 在加密上已破解
- 所有 UUID 库都支持
- 使用 SHA-1 哈希
- 160 位哈希截断为 128 位
- 在 RFC 4122 中定义
- SHA-1 在安全使用上已弃用,但比 MD5 更强
- 所有 UUID 库都支持
对于所有新开发,优先选择 UUID v5 而非 UUID v3。SHA-1 哈希比 MD5 更强,性能差异可忽略不计。仅当你需要从已使用它的系统复现 UUID 时才使用 UUID v3。
何时使用 UUID v3
UUID v3(和 v5)适用于需要从有意义名称派生稳定、可复现标识符的场景——而非需要存储和查找的随机 ID:
理解确定性
UUID v3 的确定性既是其最大优势,也是其最重要的约束。给定任何命名空间 UUID 和任何名称字符串,输出 UUID 是完全固定的——不涉及随机性。这意味着:
始终产生:9073926b-929f-31c2-abc9-fad77ae3e8eb
如果攻击者知道命名空间并能猜测名称,他们可以提前计算 UUID。UUID v3 值不应用作不可预测的令牌、会话 ID 或机密。对于任何安全敏感的标识符,请使用 UUID v4。
代码示例
UUID v3 需要命名空间 UUID 和名称字符串。使用标准 uuid 包:
// Browser / Node.js — UUID v3 without dependencies
function uuidV3(namespace, name) {
// namespace must be a UUID string like '6ba7b810-9dad-11d1-80b4-00c04fd430c8'
const nsBytes = namespace.replace(/-/g, '').match(/../g).map(h => parseInt(h, 16))
const nameBytes = [...new TextEncoder().encode(name)]
const combined = new Uint8Array([...nsBytes, ...nameBytes])
// md5(combined) — use your preferred MD5 library or the inline implementation
const hash = md5(combined) // returns Uint8Array(16)
hash[6] = (hash[6] & 0x0f) | 0x30 // version 3
hash[8] = (hash[8] & 0x3f) | 0x80 // variant
const h = [...hash].map(b => b.toString(16).padStart(2, '0')).join('')
return `${h.slice(0,8)}-${h.slice(8,12)}-${h.slice(12,16)}-${h.slice(16,20)}-${h.slice(20)}`
}
// Using the 'uuid' npm package
import { v3 as uuidv3 } from 'uuid'
const DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'
console.log(uuidv3('example.com', uuidv3.DNS))
// → '9073926b-929f-31c2-abc9-fad77ae3e8eb' (always the same)import uuid
# Using the standard library
dns_uuid = uuid.uuid3(uuid.NAMESPACE_DNS, 'example.com')
print(dns_uuid)
# → 9073926b-929f-31c2-abc9-fad77ae3e8eb
url_uuid = uuid.uuid3(uuid.NAMESPACE_URL, 'https://example.com/page')
print(url_uuid)
# Custom namespace
MY_NS = uuid.UUID('a1b2c3d4-e5f6-7890-abcd-ef1234567890')
custom = uuid.uuid3(MY_NS, 'my-entity-name')
print(custom)package main
import (
"fmt"
"github.com/google/uuid"
)
func main() {
// Standard DNS namespace
ns := uuid.MustParse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
id := uuid.NewMD5(ns, []byte("example.com"))
fmt.Println(id)
// → 9073926b-929f-31c2-abc9-fad77ae3e8eb
// URL namespace
urlNS := uuid.MustParse("6ba7b811-9dad-11d1-80b4-00c04fd430c8")
idURL := uuid.NewMD5(urlNS, []byte("https://example.com/page"))
fmt.Println(idURL)
}