【问题标题】:Nonce generation with DateTime Tick count使用 DateTime Tick 计数生成 Nonce
【发布时间】:2019-08-24 14:20:51
【问题描述】:

在我们的网络应用程序中,我们使用外部服务来实现特定功能。要请求该外部服务,我们必须在请求标头中添加一个 key,它是一个整数,并且对我的所有请求都是唯一的,技术上称为 nonce

我使用了随机数生成

var nonce = (long) DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).Ticks*100 + random.Next(100);

现在,在 100 个并发请求中,密钥被复制。密钥是如何复制的?

我不能使用 GUID,因为我需要不断增加整数值。

【问题讨论】:

  • 时间不是随机数熵的良好来源。为什么不使用GUIDs?
  • 如果您有真正的并发请求,那么DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).Ticks*100 是这些请求的常量。那么你只剩下random.Next(100)了。那时发生碰撞并不需要太多。一个简单(但不理想)的选择是简单地做random.Next()。
  • @ArthurAttout 我需要不断增加整数值。
  • 为什么需要它增加?根据您的要求(以及 Nonce 这个词的自然含义),该数字只需是唯一的。 GUID 将对此非常有用(它们不会是唯一的,但您发生冲突的可能性极低)
  • (顺便说一句,您的初始代码也不能保证您的号码会不断增加)

标签: c# nonce


【解决方案1】:

如果您有真正的并发请求,那么DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).Ticks * 100 是这些请求的常量。那么你只剩下random.Next(100) 了,那么就不会发生碰撞了。一个简单(但不理想)的选择是简单地做random.Next()。

一个更好的主意是:

[ThreadStatic]
private static Random __random = new Random();
private static int shift = 32;
private static long counter = 0L;

public long GenerateNextNonce()
{
    var major = ++counter << shift;
    var minor = (DateTime.UtcNow.Ticks ^ __random.Next()) & (1L << shift - 1);
    return major + minor;
}

++counter 确保您有一个不断增加的数字序列 - 仅此一项就足以产生随机数,但它具有高度可预测性,因此很容易被黑客攻击。

计算DateTime.UtcNow.Ticks ^ __random.Next() 确保了一个相当随机的数字,它不完全依赖于Random 的实现,因此它确保了这个数字非常不可预测,但不一定会增加。 p>

使用shift 值可确保counter 值转移到数字的“高端”或主要部分。调用 (DateTime.UtcNow.Ticks ^ __random.Next()) &amp; (1L &lt;&lt; shift - 1) 会截断 nonce 随机部分的高端位,确保次要值不与主要编号共享任何位。

我以32 的shift 值运行此程序,并产生了100_000_000 值,并且只用尽了不到5% 的可用数字,朝向long.MaxValue。只要你生产的随机数少于 20 亿,你就应该是好的。如果您想要更多,请减少 shift。

【讨论】:

    【解决方案2】:

    我猜这个问题是因为random.Next(100)。

    根据documentation,random.Next 返回一个小于 100 的非负值。 在 100 个并发请求之后,此方法可能会返回相同的值。

    正如上述 cmets 中所建议的,您应该选择 GUID,因为它们相同的可能性极低。

    否则,如果您不想要 GUID,那么您可以尝试以下代码(取自 blog)。

    它应该可以帮助您解决问题。

    public static string GetNonce()
    {
        // better to get unique random number if 
        // called mulitple times
        Random r = RandomProvider.GetThreadRandom(); 
    
        DateTime created = DateTime.Now;
    
        string nonce = Convert.ToBase64String(Encoding.ASCII.GetBytes(SHA1Encrypt(created + r.Next().ToString())));
    
        return nonce;
    }
    

    希望这会有所帮助。

    【讨论】:

    • “GUID,因为它们永远是唯一的” - 好吧,你能说的最好的就是它们相同的可能性极低。
    • 感谢@Enigmativity!我在输入答案时也在考虑同样的问题。但最初避免了这种情况,因为我不确定在问题的上下文中是否需要该细节。但无论如何,我现在已经在答案中添加了这一点。
    • @Moshii - 您是否尝试过答案中的 GetNonce 方法?它是否适用于您的程序期望的并发级别?
    • @ManojChoudhari 正如我在我的网络应用程序中所说,我向另一个服务发出 http 请求,而 api 只接受整数值。
    • @Moshii - 你能提到“随机”变量的范围是什么吗?它是不是每次你想生成 nonce 时都创建的,它是同一个应用程序范围的?
    猜你喜欢
    • 2016-03-29
    • 2017-06-02
    • 2020-02-23
    • 1970-01-01
    • 2014-09-09
    • 1970-01-01
    • 2013-04-18
    • 2017-02-21
    • 1970-01-01
    相关资源
    最近更新 更多