HMACSHA1.ComputeHash() 线程安全问题

发布于 2024-07-14 03:05:03 字数 409 浏览 8 评论 0原文

我问自己,在 ASP.NET 页面的代码隐藏中使用包含 HMACSHA1 实例的静态(共享)变量是否会很危险。 问题是,在同一 ASP.NET 页面上处理多个同时请求时,所有 ASP.NET 工作进程线程将使用相同的 HMACSHA1 实例。 由 ComputeHash() 使用/修改的所有 (HMACSHA1) 实例和 ComputeHash() 方法变量将由所有线程共享(= 可以修改)?! 这个假设正确吗? 结果ComputeHash的返回值就不能保证正确了?!?! 因此,我不允许在所有 asp.net 线程上使用静态/共享 HMACSHA1 实例。

我只是想知道您对这个问题的看法。

唯一的解决方案是在 ComputeHash() 方法中添加关键路径等。 但这是“我们力所能及的”..

问候, 克里斯

i am asking myself if it would be dangerous on a asp.net page´s codebehind to use an static (Shared) variable which holds an HMACSHA1-instance. the problem is that the same HMACSHA1-instance would be used by all the asp.net worker-process´ threads when processing multiple simultaneous requests on the same asp.net-page.
all (HMACSHA1)instance- and ComputeHash()-method variables which are used/modified by ComputeHash() would be shared (= could be modified) by all the threads?! is that assumption correct?
as a result the return value of ComputeHash would not be guaranteed to be correct?!?!
thus i am not allowed to use an static/Shared HMACSHA1-instance over all the asp.net-threads..

i am just wondering what you think about this problem.

the only solution to this would be sth like an critical path etc in the ComputeHash()-method. but that is "out of our reach"..

regards,
kris

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

时光清浅 2024-07-21 03:05:03

当我在四核 HT cpu 上运行 8 或 16 个并行任务(其中包括执行哈希计算)时,我刚刚收到来自 SHA256Cng.ComputeHash 的未知加密异常。

在 ComputeHash 周围添加锁定语义解决了这个问题 - 所以看起来至少 SHA256Cng 版本不是线程安全的。

I just got an unknown cryptographic exception form the SHA256Cng.ComputeHash, when running 8 or 16 parallel tasks that amongst other things performed the hash computation, on a quad-core HT cpu.

Adding locking semantics around ComputeHash solved the issue - so it seems that at least the SHA256Cng version is not thread safe.

伴我心暖 2024-07-21 03:05:03

哈希算法是确定性的,它们每次都必须为给定的输入返回相同的哈希值。

只要您每次使用相同的密钥,就无需将它们设为静态。 但是,如果您使用无参数构造函数构造 HMACSHA1 实例,那么它会生成一个随机密钥。 您应该从 KeyValue 属性中获取随机值并将其与哈希值一起存储。

使用静态实例肯定是危险的。 如果Thread1设置了要计算的值,然后Thread2在Thread1调用ComputerHash()之前设置了该值,那么Thread1将获得Thread2值的哈希值。 如果任一线程设置密钥,也会发生同样的情况。

Hashing algorithms are deterministic, they must return the same hash for a given input every time.

As long as you use the same key each time then there's no need to make them static. However if you're constructing the HMACSHA1 instance with the parameterless constructor then it generates a random key. You should be taking the random value from the KeyValue property and storing it with the hash.

It is definitely dangerous to use a static instance. If Thread1 sets the value to be calculated, and then Thread2 sets the value before Thread1 calls ComputerHash() then Thread1 is going to get the hash of Thread2's value. The same will happen if either thread is setting the key.

高冷爸爸 2024-07-21 03:05:03

值得注意的是,KeyedHashAlgorithm.ComputeHash() 不是线程安全的,因为它对于相同的 KeyedHashAlgorithm.Key 给出了不确定的结果。

就我而言,我想缓存 KeyedHashAlgorithm,因为我的 KeyedHashAlgorithm.Key 始终相同,以从客户端验证真实性。 我意识到 ComputeHash() 不一致,可能它将内部变量缓存到 KeyedHashAlgorithm 实例中。 我应该缓存每个线程 ThreadStatic 或 ThreadLocal 的实例。 这是测试:

静态 KeyedHashAlgorithm 给出不一致的结果:

var kha = KeyedHashAlgorithm.Create("HMACSHA256");
kha.Key = Encoding.UTF8.GetBytes("key");
Action comp = () =>
{
    var computed = kha.ComputeHash(Encoding.UTF8.GetBytes("message"));
    Console.WriteLine(Convert.ToBase64String(computed));
};
Parallel.Invoke(comp, comp, comp, comp, comp, comp, comp, comp);

与每个线程的 KeyedHashAlgorithm 相比:

ThreadLocal<KeyedHashAlgorithm> tl= new ThreadLocal<KeyedHashAlgorithm>(() =>
{
    var kha = KeyedHashAlgorithm.Create("HMACSHA256");
    kha.Key = Encoding.UTF8.GetBytes("key");
    return kha;
});
Action comp = () =>
{
    var computed = tl.Value.ComputeHash(Encoding.UTF8.GetBytes("message"));
    Console.WriteLine(Convert.ToBase64String(computed));
};
Parallel.Invoke(comp, comp, comp, comp, comp, comp, comp, comp);

此代码可用于测试其他函数的“线程安全”结果。 希望这会帮助其他人。

It worth to know that KeyedHashAlgorithm.ComputeHash() is not thread safe because it give non-deterministic result for the same KeyedHashAlgorithm.Key.

In my case, I want to cache KeyedHashAlgorithm since my KeyedHashAlgorithm.Key is always the same to verify the authenticity from client side. I realize that ComputeHash() is not consistent, probably it cache internal variable into the KeyedHashAlgorithm instance. I should cache the instance per thread ThreadStatic or ThreadLocal. This is the test:

Static KeyedHashAlgorithm gives inconsistent result:

var kha = KeyedHashAlgorithm.Create("HMACSHA256");
kha.Key = Encoding.UTF8.GetBytes("key");
Action comp = () =>
{
    var computed = kha.ComputeHash(Encoding.UTF8.GetBytes("message"));
    Console.WriteLine(Convert.ToBase64String(computed));
};
Parallel.Invoke(comp, comp, comp, comp, comp, comp, comp, comp);

Compared to KeyedHashAlgorithm per thread:

ThreadLocal<KeyedHashAlgorithm> tl= new ThreadLocal<KeyedHashAlgorithm>(() =>
{
    var kha = KeyedHashAlgorithm.Create("HMACSHA256");
    kha.Key = Encoding.UTF8.GetBytes("key");
    return kha;
});
Action comp = () =>
{
    var computed = tl.Value.ComputeHash(Encoding.UTF8.GetBytes("message"));
    Console.WriteLine(Convert.ToBase64String(computed));
};
Parallel.Invoke(comp, comp, comp, comp, comp, comp, comp, comp);

This code can be use to test other functions for 'thread safety' result. Hope this will help others.

猫卆 2024-07-21 03:05:03

如果您希望在不锁定的情况下实现线程安全,则可以使用 ThreadStatic 属性在每个线程上创建一个唯一的实例,如下所示:

[ThreadStatic]
private static HMACSHA1 _hmacSha1;

public static HMACSHA1 HmacSha1
{
    get 
    {
        if (_hmacSha1 == null)
        {
            // this will happen once on each thread
            _hmacSha1 = new HMACSHA1(GetKeyBytes());
        }               

        return _hmacSha1;
    }
}

现在,有两个旁注:

  1. 访问线程静态字段比访问普通静态字段所需的时间要长得多。 因此,线程静态版本可能会也可能不会更适合您。

  2. 如果您对每个页面请求执行一次此操作,那么差异将非常微小,以至于您选择哪种方法都无关紧要。 如果您在一个非常紧密的循环中执行此操作,或者锁定部分中的代码花费了很长时间,那么选择可能很重要。

If you want thread safety without locking, you can use the ThreadStatic attribute to create a unique instance on each thread like this:

[ThreadStatic]
private static HMACSHA1 _hmacSha1;

public static HMACSHA1 HmacSha1
{
    get 
    {
        if (_hmacSha1 == null)
        {
            // this will happen once on each thread
            _hmacSha1 = new HMACSHA1(GetKeyBytes());
        }               

        return _hmacSha1;
    }
}

Now, two side notes:

  1. Accessing a thread-static field takes significantly longer than accessing a normal static field. So the thread-static version may or may not be better for you.

  2. If you're doing this once per page request, then the difference will be so minuscule that it won't matter which approach you choose. If you were doing this in a very tight loop, or the code in your lock section took a very long time, then the choice could be important.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文