在许多客户端和服务器上生成真正全球唯一的ID

时间:2012-05-22 07:54:59

标签: java javascript flash guid

摘要

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。

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

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

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

关键问题

  • 基于随机或复合?
  • 包含系统ID?
  • 如果系统ID:生成随机系统ID或使用中央注册表?
  • 包括时间戳或其他一些nonce?
  • 要哈希还是不哈希?

5 个答案:

答案 0 :(得分:4)

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

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

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

可能有助于查看distributed hashing的方法,该方法用于在对等环境中唯一标识和定位片段。考虑到你有一个可以干预以断言唯一性的服务器,这可能会有点过分。

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

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

<强>现时标志: nonce / salt / random种子将用于混淆或以其他方式加扰ID。当您不希望其他人能够猜出ID的原始值时,这很重要。如果这是必要的,那么最好使用私有加密密钥加密ID,并将公共解密密钥传递给需要读取ID的每个消费者。

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

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

答案 1 :(得分:2)

快速而肮脏的东西,也可能无法用于您的用例 -

使用Java的UUID并将其与诸如clientName之类的东西联系起来。 这应解决multiple client and multiple server问题。

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

您可以编写一个java模块来生成ID,然后让Flash与该模块通信。 供您参考,您可以参考 -
Is unique id generation using UUID really unique?
Getting java and flash to talk to each other

答案 2 :(得分:2)

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

  1. 使用客户端名称,高分辨率时间以及可选的其他伪随机种子
  2. 散列数据以生成UID(或者,直接使用UUID)
  3. 将结果记录到中央服务器以进入数据库
  4. 将任何碰撞视为突出标记的错误,而不是作为值得特殊代码的情况。
  5. 使用UUID或相当长的哈希值,重复或零的可能性。所以:

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

    这样,ID在客户端生成,与服务器的联系是单向的,操作上不重要,种子不必是随机的,散列模糊了ID的来源等等避免构造碰撞,你可以确信没有碰撞。 (如果你测试了碰撞检测代码!)在这种情况下,甚至UUID也足够了。

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

答案 3 :(得分:1)

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

每个客户端连接都会获得此ID,并附带服务器发出的唯一标识符。此唯一密钥必须对此服务器是唯一的,但另一个服务器可能会向不同的客户端发出相同的ID。

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

将这三者结合起来将保证在整个系统中真正唯一的全局ID,最终ID将如下所示:

[server id][client id][request id]

答案 4 :(得分:-2)

虽然这会增加不必要的开销,但只能在一台计算机上生成 TRULY 唯一ID。添加更多,你拥有的只是概率。

我的建议是,如果你真的绝望地需要一个全局唯一的id,请查询uid的set服务器。

然而,这可能是您逻辑中的设计缺陷,因为大多数需要唯一标识符的应用程序需要它与服务器交互,在这种情况下,SERVER应首先为uid提供服务

相关问题