在许多客户端和服务器上生成真正的全局唯一 ID总结详建议的解决方案关键问题

2022-09-04 22:25:48

总结

闪存和/或javascript客户端中真正全局唯一的ID。我可以使用当前浏览器/闪存中可用的 RNG 执行此操作,还是必须构建具有服务器端随机性的复合 ID?

我需要为对象生成全局唯一标识符。我有多个用java编写的服务器端“系统”,需要能够交换ID;这些系统中的每一个都有一组 flex/javascript 客户端,这些客户端实际上为新对象生成 ID。我需要保证跨一组不相关系统的全局唯一性;例如,我需要能够合并/同步两个独立系统的数据库。我必须保证这些id之间永远不会发生冲突,并且一旦创建,我就永远不需要更改对象的ID。我需要能够在flash和javascript客户端中生成id,而无需为每个ID联系服务器。依赖于某些服务器提供的种子或系统 ID 的解决方案是可以的,只要不经常联系服务器即可。最好是完全断开连接的解决方案。同样,不需要预先注册系统的解决方案比依赖于中央机构(如 MAC 地址中的 OUI)的解决方案更可取。

我知道显而易见的解决方案是“使用UUID生成器”,例如闪存中的UIDUtil。此功能明确声明全局唯一性。总的来说,我担心依靠PRNG来保证全局唯一性。

建议的解决方案

完全依赖于客户端中的安全随机数生成器。

Flash 11+有flash.crypto.generateRandomBytes;Javascript有window.crypto,但它很新,在IE中不受支持。有像sjcl这样的解决方案,使用鼠标来添加熵。

我知道,给定一个完美的RNG,2122随机UID的碰撞可能性很小,但我担心我实际上不会在javascript或flash客户端中获得这种程度的随机性。我进一步担心,即使是加密RNG的典型用例也与我的不同:对于会话密钥等,只要攻击者无法预测,碰撞是可以接受的。就我而言,碰撞是完全不可接受的。我真的应该依靠安全 RNG 的原始输出来获得唯一 ID 吗?

生成包含系统、会话和对象 ID 的复合 ID。

一个明显的实现是在服务器安装时创建一个系统UUID,保留每个客户端登录会话ID(例如在数据库中),然后将系统和会话ID发送到客户端,该客户端将保留每个会话计数器。uid将是三重:系统ID,会话ID,客户端计数器。

我可以想象直接将它们连接起来,或者用加密哈希对它们进行哈希处理。我担心哈希本身可能会引入冲突,特别是如果哈希的输入与输出的大小大致相同。但是哈希会掩盖系统ID和可能泄漏信息的计数器。

另一种解决方案是使用一个中央注册表来分发唯一的系统 ID,而不是在安装时生成系统 ID,有点像 DOI 所做的。然而,这需要更多的协调,但我想这是真正保证全球一致性的唯一途径。

关键问题

  • 基于随机还是基于复合?
  • 是否包括系统 ID?
  • 如果系统 ID:生成随机系统 ID 或使用中央注册表?
  • 包括时间戳或其他随机数?
  • 散列还是不散列?

答案 1

最简单的答案是使用服务器分配的客户机ID,该ID为每个客户机递增,并在每个客户机上使用一个值,该值为该客户机上的每个片段递增。客户端 ID 和片段 ID 对将成为该内容的全局唯一 ID。

另一种简单的方法是在服务器上生成一组唯一的ID(比如一次2k),并将它们批量发送到每个客户端。当客户端的 ID 用完时,它会联系服务器以获取更多信息。

客户端 ID 应存储在所有服务器均可访问的中央存储库中。

它可能有助于查看分布式哈希的方法,该方法用于在对等环境中唯一标识和定位片段。考虑到您有一台可以进行干预以断言唯一性的服务器,这可能有些过分。

要回答您的问题,您需要确定系统ID,随机数或哈希增加的复杂性会带来的好处。

系统标识:系统 ID 通常用于唯一标识域中的系统。因此,如果您不关心用户是谁,或者有多少会话处于打开状态,而只想确保您知道设备是谁,请使用系统 ID。这在以用户为中心的环境(如 JavaScript 或 Flash)中通常不太有用,在这些环境中,用户或会话可能相关。

随机数:随机数/盐/随机种子将用于混淆或以其他方式扰乱ID。当您不希望其他人能够猜测 ID 的原始值时,这一点很重要。如果这是必要的,那么最好使用私有加密密钥加密ID,并将公共解密密钥传递给需要读取ID的每个消费者。

时间戳:考虑到客户端时钟的可变性(即您无法保证它遵循任何时间或时区),时间戳需要被视为此应用程序的伪随机值。

散 列:虽然哈希通常(ab)用于创建唯一键,但它们的真正目的是将一个大的(可能是无限的)域映射到一个更小,更易于管理的域。例如,MD5 通常用于从时间戳、随机数和/或随机数数据生成唯一 ID。实际发生的事情是,MD5函数正在将无限范围的数据映射到2 ^ 128种可能性的空间。虽然这是一个巨大的空间,但它不是无限的,所以逻辑告诉你,将有(即使只是在理论上)相同的哈希分配给两个不同的片段。另一方面,完美的散列尝试为每个数据片段分配一个唯一的标识符,但是如果您只是为每个客户端片段分配一个唯一标识符,这是完全不必要的。


答案 2

一些快速而肮脏的东西,也可能不适合你的用例 -

使用Java的UUID并将其与类似的东西耦合,比如客户端名称。这应该可以解决问题。multiple client and multiple server

这背后的基本原理是,在同一纳秒内获得2次调用的可能性很低,请参阅下面提供的链接。现在,通过将 clientName 与 UUID 耦合,您可以确保跨客户端的唯一 ID,并且应该只处理同一客户端在同一纳秒内调用两次的用例。

您可以编写一个java模块来生成ID,然后让Flash与此模块进行通信。供您参考,您可以参考 --
使用 UUID 的唯一 ID 生成真的是唯一的吗?
让java和flash相互通信