12

概括

Flash 和/或 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,2 122随机 UID 的碰撞可能性很小,但我担心我实际上不会在 javascript 或 flash 客户端中获得这种程度的随机性。我进一步担心,即使是加密 RNG 的典型用例也与我的不同:对于会话密钥等,只要攻击者无法预测冲突,冲突是可以接受的。就我而言,碰撞是完全不可接受的。 我真的应该依赖安全 RNG 的原始输出来获取唯一 ID 吗?

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

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

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

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

关键问题

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

4 回答 4

4

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

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

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

它可能有助于查看用于在对等环境中唯一标识和定位片段的分布式散列方法。考虑到您有一个可以干预以断言唯一性的服务器,这可能有点过头了。

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

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

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

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

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

于 2012-05-22T13:10:50.133 回答
2

中间立场建立在@ping 的回答之上:

  1. 使用客户端名称、高分辨率时间和可选的其他一些伪随机种子
  2. 散列数据以生成 UID(或者,直接使用 UUID)
  3. 将结果记录到中央服务器以输入数据库
  4. 将任何冲突视为突出标记的错误,而不是需要特殊代码的情况。

使用 UUID 或相当长的哈希,重复或为零的机会。所以要么:

A)在应用程序的整个生命周期中,您不会得到重复,生活是美好的。B) 几十年后你会看到一个重复的,或者可能是两个(怪异的!)。手动干预以处理这些情况;如果您使用客户端运行服务器,则可以负担得起。C) 如果您遇到第三次冲突,则代码存在根本性错误,可以对此进行调查并采取措施避免重复。

这样,ID 在客户端生成,与服务器的联系是单向的并且在操作上是非关键的,种子不必是随机的,散列模糊了 ID 的来源,因此避免了构造冲突,并且您可以确信没有发生碰撞。(如果您测试该碰撞检测代码!)在这种情况下,即使是 UUID 也足够了。

散列增加冲突可能性的唯一方法是原始种子信息中的信息内容接近散列的大小。这是极不可能的,但如果属实并且您仍在考虑微陨石,只需增加散列值的大小即可。

于 2014-08-07T20:57:00.757 回答
2

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

使用 Java 的 UUID 并将其与诸如 clientName 之类的东西耦合。这应该可以解决multiple client and multiple server问题。

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

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

于 2012-05-28T12:52:07.230 回答
1

我的两分钱..每个服务器锁定一个数据库表并从中获取一个 id,然后递增它。这将是服务器的唯一 ID。

每个连接的客户端都会得到这个 id,再加上服务器发出的唯一标识符。此唯一密钥对于此服务器必须是唯一的,但另一个服务器可能会向不同的客户端发出相同的 id。

最后,每个客户端都会为每个请求生成一个唯一的 id。

将这三者结合起来将保证在整个系统中具有真正唯一的全局 id,最终的 id 将类似于:

[server id][client id][request id]
于 2013-12-25T15:34:11.570 回答