这是一个加密强大的Guid吗?

时间:2013-12-10 23:36:00

标签: c# random guid

我正在使用Guid作为网站的随机匿名访问者标识符(存储为cookie客户端大小,并存储在数据库服务器端),我想要一种加密的强大方法来生成Guids(以尽量减少碰撞的机会。)

对于记录,Guid中有16个字节(或128位)。

这就是我的想法:

/// <summary>
/// Generate a cryptographically strong Guid
/// </summary>
/// <returns>a random Guid</returns>
private Guid GenerateNewGuid()
{
    byte[] guidBytes = new byte[16]; // Guids are 16 bytes long
    RNGCryptoServiceProvider random = new RNGCryptoServiceProvider();
    random.GetBytes(guidBytes);
    return new Guid(guidBytes);
}

有更好的方法吗?

修改 这将用于两个目的,访问者的唯一ID和购买的事务ID(这将简要地是查看/更新敏感信息所需的令牌)。

5 个答案:

答案 0 :(得分:4)

在回答OP的实际问题时,这是否具有加密强度,答案是肯定的,因为它是直接从 RNGCryptoServiceProvider 创建的。但是,目前接受的答案提供的解决方案绝对不是加密安全的,因为这个SO答案:

Is Microsoft's GUID generator cryptographically secure

由于理论上缺乏唯一性(使用数据库查找很容易检查),这在结构上是否是正确的方法是另一个问题。

答案 1 :(得分:0)

因此,您正在构建的内容在技术上不是GUID。 GUID是全球唯一标识符。您正在构建一个128位的随机字符串。我建议,像前一个回答者一样,你使用内置的GUID生成方法。这种方法有一个(虽然非常小)生成重复GUID的机会。

使用内置功能有一些优势,包括跨机器唯一性[部分原因是guid中引用了MAC地址,请参见此处:http://en.wikipedia.org/wiki/Globally_Unique_Identifier

无论您是否使用内置方法,我建议您不要将Purchase GUID公开给客户。 Microsoft代码使用的标准方法是公开标识客户的会话GUID,并相对快速地过期。 Cookies跟踪客户用户名和保存的密码以创建会话。因此,您的“短期购买ID”从未真正传递给客户(或者更重要的是,从客户那里收到),并且客户的个人信息与整个Interwebs之间存在更持久的隔离墙。

答案 2 :(得分:0)

碰撞在理论上是不可能的(它不是全球唯一的),但可预测性是另一个问题。正如Christopher Stevenson正确指出的那样,给定一些先前生成的GUID,实际上可以开始在比您想象的更小的键空间内预测模式。 GUID保证唯一性,而不是可预测性。大多数算法都会将其考虑在内,但您永远不应该依赖它,特别是不能作为购买的交易ID ,无论如何简单。你正在为蛮力会话劫持攻击创造一扇敞开的大门。

要创建一个正确的唯一ID,从系统中取一些随机的东西,附加一些访问者特定的信息,并在服务器上附加一个你知道的字符串,然后在整个事情上添加一个好的哈希算法。与GUID不同,哈希意味着不可预测且不可逆转。

简化:如果您关心的是唯一性,为什么不直接给所有访问者提供从1到无穷大的连续整数。保证是独一无二的,只是非常可预测,当你刚刚购买了第684项时,你可以开始在685处进行黑客攻击直到它出现。

答案 3 :(得分:0)

避免碰撞:

  1. 如果您无法保持全局计数,请使用Guid.NewGuid()
  2. 否则,增加一些整数并使用1,2,3,4 ...
  3. “但这不容易猜到吗?”

    是的,但意外和故意碰撞是不同解决方案的不同问题,最好单独解决,请注意最少,因为可预测性有助于防止意外碰撞,同时使故意碰撞更容易。

    如果可以全局递增,则数字2保证不发生冲突。 UUID被发明为一种在没有全球跟踪能力的情况下接近它的手段。

    假设我们使用递增整数。假设我们在特定情况下的ID是123.

    然后我们可以做类似的事情:

    private static string GetProtectedID(int id)
    {
      using(var sha = System.Security.Cryptography.SHA1.Create())
      {
        return string.Join("", sha.ComputeHash(Encoding.UTF8.GetBytes(hashString)).Select(b => b.ToString("X2"))) + id.ToString();
      }
    }
    

    哪个产生09C495910319E4BED2A64EA16149521C51791D8E123。要将其解码回ID,我们会这样做:

    private static int GetIDFromProtectedID(string str)
    {
      int chkID;
      if(int.TryParse(str.Substring(40), out chkID))
      {
        string chkHash = chkID.ToString() + "this is my secret seed kjٵتשڪᴻᴌḶḇᶄ™∞ﮟﻑfasdfj90213";
        using(var sha = System.Security.Cryptography.SHA1.Create())
        {
          if(string.Join("", sha.ComputeHash(Encoding.UTF8.GetBytes(hashString)).Select(b => b.ToString("X2"))) == str.Substring(0, 40))
            return chkID;
        }
      }
      return 0;//or perhaps raise an exception here.
    }
    

    即使有人猜到他们被给了123号,也不会让他们推断出122的id是B96594E536C9F10ED964EEB4E3D407F183FDA043122

    或者,这两个可以作为单独的令牌给出,依此类推。

答案 4 :(得分:-1)