C# 这是加密强Guid吗?

C# 这是加密强Guid吗?,c#,random,guid,C#,Random,Guid,我正在考虑使用Guid作为网站的随机匿名访问者标识符(既存储为cookie客户端大小,也存储在db服务器端),并且我想要一种加密功能强大的生成Guid的方法(以便最大限度地减少冲突的机会) 对于记录,Guid中有16个字节(或128位) 这就是我的想法: // ///生成加密强Guid /// ///随机Guid 私有Guid GenerateNewGuid() { byte[]guidBytes=新字节[16];//guid的长度为16字节 RNGCryptoServiceProvider

我正在考虑使用Guid作为网站的随机匿名访问者标识符(既存储为cookie客户端大小,也存储在db服务器端),并且我想要一种加密功能强大的生成Guid的方法(以便最大限度地减少冲突的机会)

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

这就是我的想法:

//
///生成加密强Guid
/// 
///随机Guid
私有Guid GenerateNewGuid()
{
byte[]guidBytes=新字节[16];//guid的长度为16字节
RNGCryptoServiceProvider random=新的RNGCryptoServiceProvider();
random.GetBytes(guidBytes);
返回新的Guid(guidBytes);
}
有更好的方法吗

编辑:
这将用于两个目的,一个是访客的唯一Id,一个是购买的交易Id(这将是查看/更新敏感信息所需的令牌)。

我通常只使用
Guid.NewGuid()


因此,从技术上讲,您构建的不是GUID。GUID是全局唯一标识符。您正在构建一个128位的随机字符串。与前面的回答一样,我建议您使用内置的GUID生成方法。此方法生成重复GUID的可能性(尽管非常小)

使用内置功能有几个优点,包括跨计算机唯一性[部分原因是guid中引用了MAC地址,请参见此处:


无论您是否使用内置方法,我建议您不要向客户公开购买GUID。Microsoft代码使用的标准方法是公开识别客户的会话GUID,并相对较快地过期。Cookie跟踪客户用户名和保存的密码以创建会话。因此,您的术语“购买ID”实际上从未传递给(或更重要的是,从)客户,并且在客户的个人信息和整个互联网络之间有一道更耐用的墙。

理论上不可能发生冲突(它不是全球唯一的,没有任何原因),但可预测性是另一个问题。正如Christopher Stevenson正确指出的,给定一些以前生成的GUI,实际上可以在比您想象的小得多的键空间内开始预测模式。GUI保证唯一性,而不是可预测性。大多数算法都会考虑到这一点,但您永远不应该这样做使用它,特别是不要将其作为购买的交易Id,不管它是多么短暂。您正在为暴力会话劫持攻击打开大门

要创建正确的唯一ID,请从系统中随机抽取一些内容,附加一些特定于访问者的信息,并在服务器上附加一个只有您知道的字符串,然后在整个过程中使用一个好的哈希算法。哈希与GUI不同,它是不可预测和不可恢复的

为了简化:如果你只关心唯一性,为什么不给所有访问者一个从1到无穷大的顺序整数呢。保证唯一性,可以预见,当你刚购买商品684时,你可以开始破解685直到它出现。

为了避免冲突:

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

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

    如果你可以全局递增,那么第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


    或者,这两者可以作为单独的令牌提供,依此类推。

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


    由于理论上缺乏唯一性,这在架构上是否是正确的方法(通过db查找很容易检查)另一个问题。

    如果您想使用普通guid尽可能减少冲突的可能性,它已经具备了您需要的所有保护。现在有了不可预测的随机id,这是不同解决方案的不同要求。那么您真正的要求是什么,没有冲突或不可预测性(在同一个键空间上发生冲突的可能性更高)?NewGuid()不是吗?我不能真正谈论算法,但我的印象是,由于可能存在大量的GUID,很难猜测系统生成的GUID。冲突非常罕见,如果您担心的话,您当然可以在数据库中附加一个约束。似乎OP主要关注唯一性,所以可预测性甚至可能是一个较小的问题。为了简单起见,假设概率一致,如果地球上每个人都拥有6亿个GUID,那么一个复制的概率大约为50%。@dspiegs冲突不是手头上的问题,而是在购买时粗暴地强制他人使用会话GUID的可能性。@Servy 1)有些仍然如此,你不知道他们将如何改变它