暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

[译] 在 MariaDB 中始终使用正确的 UUID

原创 摸鱼王者 2025-04-10
359

通用唯一标识符 (UUID) 的原始版本(现称为 UUIDv1)于 20 世纪 80 年代首次亮相。它提供的最有趣的保证是生成的 ID 能够跨空间和时间始终唯一。

为了履行这一承诺,它采用了三种元素的组合:

节点,用于标识生成 UUID 的机器。此字段过去使用IEEE MAC 地址设置。MAC 地址本身是分配给任何物理网络接口控制器的唯一标识符。这些代表 UUIDv1 的前 48 位
时间戳,用于计算从生成 UUIDv1 的时刻到 1582 年 10 月 15 日(公历开始)之间的 100 纳秒间隔数。
时钟字段用于消除在同一时间戳上生成或时钟向后设置的 UUIDv1 的歧义。
另外,它将 6 位设置为特定值以标识它是 UUIDv1。

image.png

这就是 UUIDv1 的 128 位中不同组件的排列方式。

UUIDv1 的组成方式确保了时空唯一性,这意味着如果按照规范生成 UUIDv1,几乎不可能两次生成相同的 UUIDv1。实际上,这意味着,例如,当使用 UUIDv1 作为主键时,任意数量的服务器都可以向同一张表添加记录,而无需进行协调以避免冲突。MariaDB 提供了一个生成此类 UUID 的函数,即uuid()。

虽然理论上 UUIDv1 实现是合理的,但当它与现实世界的复杂性发生冲突时,最终会显示出一些局限性。

最明显的要求是必须拥有 IEEE MAC 地址。对于没有网络接口的设备,以及随着虚拟化和容器化的出现,处理物理 MAC 地址并非理所当然。最新的 UUID RFC中提出的解决方案,实际上是在MariaDB 的 UUIDv1 实现中使用的解决方案,是随机生成一个 MAC 地址。由于 UUIDv1 的空间唯一性在现代社会难以实现,我们只剩下时间唯一性,这意味着在实践中,尽管发生 UUIDv1 冲突的可能性很小,我们仍然可以假装任何生成的 UUIDv1 都是唯一的。

UUIDv1 会泄露两个敏感信息,这会带来更严重的问题:生成 UUIDv1 的机器的 MAC 地址和生成该 UUIDv1 的时间戳。MAC 地址会导致MAC 欺骗和MAC 泛洪等漏洞,而时间戳与特定事件或信息关联时,则可能泄露用户或系统的敏感信息。此外,UUIDv1 在一定程度上具有可预测性。这种可预测性也可能被利用于诸如“三明治攻击”之类的攻击中。

主要是因为在现代环境中无法保证绝对不会发生碰撞,并且由于前面提到的安全风险,UUIDv1 被视为遗留问题,并且已经提出了克服其局限性的新版本。为了接收这些更改,我发起了两个拉取请求,这启动了最终在 MariaDB 中提供 UUIDv4 和 UUIDv7 的工作。用于生成这两种新 UUID 类型的函数是uuid_v4()和uuid_v7()。

UUIDv4 解决了因公开 MAC 地址和创建时间戳而带来的安全问题。与所有其他版本一样,此版本也设置了 6 位来指示具体版本和修订版本,然后随机生成剩余的 122 位。

image.png

UUIDv4 的 128 位结构,其特点是几乎全随机组成。
使用 UUIDv4 时仍然可能发生碰撞,但假设随机数生成器种子设置良好,生成两次相同的 122 位序列的概率非常低,因此我们可以假设碰撞永远不会发生。可以创建的不同元素数量是一个天文数字,即 2 ^122个唯一的 UUIDv4。人类很难理解如此巨大的数字,但为了直观地了解它有多大,如果我们为地球上的每一粒沙子分配一个 UUIDv4,我们使用的 UUIDv4 数量甚至还不到总数的 0.01%。

UUIDv4 相较于 UUIDv1 有了显著的改进,但它并非灵丹妙药。UUIDv4 与 UUIDv1 的主要共同问题是生成的 UUID 是随机分布的,而非自然排序的。在数据库领域,这可能会在多种情况下影响性能。通常,数据库内部使用的数据结构无法很好地处理随机插入,这会导致不连续的内存访问,并可能增加磁盘 I/O。此外,一些指令内部依赖于自然顺序,从自然顺序会降低性能的位置开始。这可能会影响范围查询、窗口函数以及诸如ORDER BY和 之类的修饰符的性能GROUP BY。

在泄露时间戳并不代表漏洞问题的用例中,例如在UUID 仅在内部使用且从不向用户公开的情况下,我们可以通过使用 UUIDv7获得自然顺序并因此获得性能。

image.png

UUIDv7 的 128 位布局,高位为 Unix 时间戳,并以随机数据完成结构。

正如RFC中所述,UUIDv7 可以通过三种不同的方式生成。我们在 MariaDB 中采用的实现是版本 3,其中:UUIDv7 的前 60 位使用精度为亚毫秒的Unix 时间戳填充,保留 6 位用于指定 UUID 的版本和修订版本,其余 62 位则填充随机数据。

总而言之,新提出的 UUID 版本(可使用函数uuid_v4()和生成uuid_v7())优于旧版 UUIDv1,后者由于其局限性应避免使用。对于优先考虑性能且 UUID 不对外公开的用例,建议使用 UUIDv7。当安全性或防止隐私数据泄露至关重要时,建议使用 UUIDv4。从MariaDB 11.7开始,UUIDv4 和 UUIDv7 均可与 UUIDv1 一起使用,让您可以根据具体用例选择最佳版本。

原文地址:https://mariadb.org/always-use-the-right-uuid/
原文作者:Stefano Petrilli

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论