在C#中生成唯一的*和*随机URL

时间:2012-09-03 00:48:25

标签: c# security authentication cryptography guid

我的最终目标是创建一个唯一且无法猜测/预测的网址。此URL的目的是允许用户执行验证其电子邮件地址和重置密码等操作。这些URL将在设定的时间内过期(目前设置为24小时)。

我最初使用Guid用于此目的,但我现在明白这是介于“正常”和“非常不安全”之间,取决于您倾听的专家。所以,我想我会加强我的代码,为了以防万一。起初我以为我只是坚持使用Guid,但是从随机字节而不是Guid.NewGuid()工厂方法生成它。这是我提出的方法:

public static Guid GetRandomGuid()
{
    var bytes = new byte[16];
    var generator = new RNGCryptoServiceProvider();
    generator.GetBytes(bytes);
    return new Guid(bytes);
}

我不太清楚使用new Guid(bytes)而不是Guid.NewGuid()时究竟发生了什么,但我认为所有这些方法都会产生随机字节数组和存储它在Guid数据结构中。换句话说,它不再保证是唯一的,它只能保证是随机的。

由于我的网址必须是唯一的随机,因此这似乎不是一个可靠的解决方案。我现在想,我应该将我的URL基于一个唯一ID(可以是Guid或者,如果可用的话,数据库自动增加的id)和从{{1生成的随机序列}}

问题

生成验证/密码重置网址的最佳方法是什么,该网址既保证唯一又极难/无法预测/猜测?

  • 我应该通过将唯一字符串与随机字符串连接来构建我的URL吗?

  • .NET Framework是否有内置方法可以轻松生成可用于URL的唯一随机(不可预测)序列?

  • 如果没有,是否有可用的开源解决方案?

更新

如果有人有类似要求,我目前正在使用以下方法:

RNGCryptoServiceProvider

如果您发现此问题,请发表评论。

5 个答案:

答案 0 :(得分:5)

Guid并不是一种安全功能。创建Guid make no claims about how secure it is的标准,或猜测它是多么容易/多难。 它只是声称它的独特性。

如果您尝试使用Guid来保护您的系统,那么您将没有安全的系统。

答案 1 :(得分:0)

[编辑:我错过了上面对RNGCryptoServiceProvider的调用。对此抱歉。]

RNG生成器(例如RNGCryptoServiceProvider)的问题在于它们不能保证唯一性。如你所知,Guids statistically unlikely是唯一的,但不保证。保证唯一性和随机性的唯一真正方法是生成GUID,然后将其放在可搜索的存储中,如数据库表。无论何时生成新值,请检查它是否已存在。如果是,则丢弃它并生成新值。

答案 2 :(得分:0)

你可以生成128位,"随机,"通过使用随机密钥键入的AES计数器运行计数器的唯一号码。只要使用相同的密钥,就不会重复任何输出。

static byte[] AESCounter(byte[] key, ulong counter) {
    byte[] InputBlock = new byte[16];
    InputBlock[0] = (byte)(counter & 0xffL);
    InputBlock[1] = (byte)((counter & 0xff00L) >> 8);
    InputBlock[2] = (byte)((counter & 0xff0000L) >> 16);
    InputBlock[3] = (byte)((counter & 0xff000000L) >> 24);
    InputBlock[4] = (byte)((counter & 0xff00000000L) >> 32);
    InputBlock[5] = (byte)((counter & 0xff0000000000L) >> 40);
    InputBlock[6] = (byte)((counter & 0xff000000000000L) >> 48);
    InputBlock[7] = (byte)((counter & 0xff00000000000000L) >> 54);
    using (AesCryptoServiceProvider AES = new AesCryptoServiceProvider())
    {
        AES.Key = key;
        AES.Mode = CipherMode.ECB;
        AES.Padding = PaddingMode.None;
        using (ICryptoTransform Encryptor = AES.CreateEncryptor())
        {
            return Encryptor.TransformFinalBlock(InputBlock, 0, 16);
        }
    }
}

答案 3 :(得分:0)

获取所有用户登录凭据的md5并将其与Guid.NewGuid()生成的guid连接.ToString()并在您的URL中使用它,它应该可以正常工作。

答案 4 :(得分:0)

使用linkID和Datesent列在数据库中创建一个表,在生成链接发送insert DateTime.Now到表中并返回linkId时,将linkID设置为activationLink上的querystring参数。

在加载激活页面时,请检索linkId并使用它来唤起存储过程,该过程将在传递相应的linkId作为参数时返回日期,当您获得日期时,您可以添加您希望链接的时间长度使用.AddDays() / .AddMonths保持活动状态(这是日期时间的C#方法)。然后将您回来的日期与今天的日期进行比较。如果已经过了几天或几个月的长度,则会显示错误消息,或者继续并显示页面内容。

我认为您将页面内容保留在面板中并将其设置为visible = "false",然后仅在日期仍在范围内时才设置面板visible="true"