Sql server CRYPT_GEN_RANDOM足够独特吗?

Sql server CRYPT_GEN_RANDOM足够独特吗?,sql-server,uniqueidentifier,Sql Server,Uniqueidentifier,我正在使用以下内容生成一个令牌 SET @Token = CAST(CRYPT_GEN_RANDOM(16) AS UNIQUEIDENTIFIER) 令牌将在URL中可见,并且应该是唯一的 使用它是个好主意吗?以这种方式生成的“GUID”不是真正的GUID,因为GUID中保留的用于指示GUID的变体和版本的位也是随机的。实际上,大多数工具根本不关心或查看GUID的位,但可以想象的是,某些系统或未来版本的GUID位模式存在无效问题。你不必担心冲突,因为剩下的部分是随机的,但这仍然很难看 对于(

我正在使用以下内容生成一个令牌

SET @Token = CAST(CRYPT_GEN_RANDOM(16) AS UNIQUEIDENTIFIER)
令牌将在URL中可见,并且应该是唯一的

使用它是个好主意吗?

以这种方式生成的“GUID”不是真正的GUID,因为GUID中保留的用于指示GUID的变体和版本的位也是随机的。实际上,大多数工具根本不关心或查看GUID的位,但可以想象的是,某些系统或未来版本的GUID位模式存在无效问题。你不必担心冲突,因为剩下的部分是随机的,但这仍然很难看

对于(加密)随机GUID,您需要具有版本4、变体1的GUID。四位表示版本,两位表示变体1,留下122个随机位,应该足够了。在T-SQL中正确设置这些位并不直观,但可行:

SELECT CONVERT(UNIQUEIDENTIFIER,
    CRYPT_GEN_RANDOM(7) + 
    -- Set version = 4
    CONVERT(BINARY(1), (CRYPT_GEN_RANDOM(1) & 15) | 64) +
    -- Set variant = 1
    CONVERT(BINARY(1), (CRYPT_GEN_RANDOM(1) & 63) | 128) +
    CRYPT_GEN_RANDOM(7) 
)
位和字节的位置不是直观的,因为SQLServer对它们的编码是错误的

也可考虑以下备选方案:

  • 对于一个令牌,使用plain,几乎不担心攻击者可能猜到下一个值,否则安全性不会受到影响。请记住,这通常至少需要能够随意生成一块guid,最坏的情况是需要访问生成guid的机器的内存。前者可以限制利率,后者意味着游戏可能已经结束了
  • 使用随机字节,不要假装它是GUID,并将其转换为十六进制字符串,如通过(例如)
    selectconvert(CHAR(32)、CRYPT\u GEN\u random(16)、2)
    (使用
    selectconvert(BINARY(16)、@s,2)
    获得的。字符串比GUID更容易传递,所以很难理解为什么这里绝对需要GUID。你还得到了6个完整的随机性。二进制(16)列的大小与UNIQUEIDENTIFIER的大小相同,因此存储也不是问题。(但您可能希望考虑使用String列,以在将来留出新的令牌格式的开放空间))

  • 好主意很广泛。您提出的唯一真正的问题是它是否唯一。我在这里看到的问题是您没有控制GUID的类型。应该只随机生成类型4的guid,但是您的值可以声明为其他类型,因此会与已经使用的值发生冲突。换句话说,可以生成16个随机字节。一般来说,将结果强制转换为带有附加语义的GUID/uniqueidentifier是不好的。这将无法获得有效的GUID。特别是,GUID的“类型”位将随机填充。如果您想要16个安全的随机字节,那么就获得16个随机字节,但不要假装它们是GUID。只需将令牌作为十六进制字符串传递,这样就不会出现混淆(
    CONVERT(VARCHAR(32),CRYPT\u GEN\u RANDOM(16),2)
    )。假装它是一个GUID的问题是,不可避免地,有人会在某个地方实际使用
    NEWID()
    ,认为这没问题,因为GUID不应该是安全的。在这种情况下使用合适的类型。如果您想要一个既随机又唯一的GUID,并且您不介意生成一个GUID的时间比使用
    NEWID()
    要长一点,那么您仍然可以使用
    CRYPT\u GEN\u random()
    生成随机位,然后正确设置“type”和“version”位。这将为您提供122位加密安全性,这可能就足够了。阅读血淋淋的细节。如果您不想要或不需要该结构,请使用16个字节,但不要强制转换为
    uniqueidentifier
    /
    guid
    ,并声明您实际上没有遵守的结构。