SHA1Managed.ComputeHash在不同的服务器上偶尔会有所不同

JAL*_*RED 7 c# hash encoding sha1

背景(您可以跳过本节)

我有大量的数据(大约3 MB)需要在几百台机器上保持最新.有些机器运行C#,有些运行Java.数据可能随时发生变化,需要在几分钟内传达给客户.数据以4个负载平衡服务器以Json格式提供.这4台服务器运行的是带有Mvc 3和C#4.0的ASP.NET 4.0.

在4台服务器上运行的代码具有散列算法,该算法散列Json响应,然后将散列转换为字符串.此哈希值将提供给客户端.然后,每隔几分钟,客户端使用散列ping服务器,如果散列已过期,则返回新的Json对象.如果散列仍然是当前的,则返回具有emptry体的304.

有时,4个框生成的哈希在框中不一致,这意味着客户端不断下载数据(每个请求可能会遇到不同的服务器).

代码Snipet

以下是用于生成哈希的代码.

internal static HashAlgorithm Hasher { get; set; }
...
Hasher = new SHA1Managed();
...
Convert.ToBase64String(Hasher.ComputeHash(Encoding.ASCII.GetBytes(jsonString)));
Run Code Online (Sandbox Code Playgroud)

为了尝试调试问题,我将其拆分为:

Prehash = PreHashBuilder.ToString();
ASCIIBytes = Encoding.ASCII.GetBytes(Prehash);
HashedBytes = Hasher.ComputeHash(ASCIIBytes);
Hash = Convert.ToBase64String(HashedBytes);
Run Code Online (Sandbox Code Playgroud)

然后我添加了一个吐出上述值的路线,并使用Beyond Compare来比较差异.

使用以下命令将字节数组转换为字符串格式以供BeyondCompare使用:

private static string GetString(byte[] bytes)
{
    StringBuilder sb = new StringBuilder();
    foreach (byte b in bytes)
    {
        sb.Append(b);
    }
    return sb.ToString();
} 
Run Code Online (Sandbox Code Playgroud)

如您所见,字节数组作为字节序列显示在字面上.它不是'转换'.

问题

我发现Prehash和ASCIIBytes值相同,但HashedBytes值不同 - 这意味着Hash也不同.

我在4个服务器盒上重启了几次IIS WebSite,当它们有不同的哈希时,比较BeyondCompare中的值.在每一个案例中,它都是"HashedBytes"值不同(SHA1Managed.ComputeHash(...)的结果)

问题

我究竟做错了什么?ComputeHash函数的输入是相同的.SHA1Managed机器是否依赖?这并不是因为因为4台机器有一半的时间具有相同的哈希值.

我搜索过StackOverFlow和Bing但是却无法找到其他任何有这个问题的人.我能找到的最接近的是那些编码有问题的人,但我想我已经证明编码不是问题.

产量

我希望不要把所有东西都放在这里,因为它有多长,但这里是我正在比较的转储的狙击:

哈希:o1ZxBaVuU6OhE6De96wJXUvmz3M =
HashedBytes:163861135165110831631611916022224717299375230207115
ASCIIBytes:.... Prehash:...

当我比较不同服务器上的两个页面时,ASCII字节相同但HashedBytes不相同.我用于字节的转储方法没有转换,它只是按顺序转储每个字节.我可以使用'.'来分隔字节.我想.

跟进 我已经对b.ToString(CultureInfo.InvariantCulture)进行了更改,并使HashAlgorithm成为局部变量而不是静态属性.我在等待代码部署到服务器.

JAL*_*RED 11

我一直在尝试复制该问题,但是一旦我将SHA1Managed属性设置为局部变量而不是全局静态,我就无法这样做.

问题在于多线程.我的代码是线程安全的,除了我标记为静态的SHA1Managed类.我假设SHA1Managed.ComputeHash在下面是线程安全的,但显然它不是标记为内部静态.

重复一遍,如果标记为内部静态,则SHA1Managed.ComputeHash不是线程安全的.

MSDN声明:

Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.
Run Code Online (Sandbox Code Playgroud)

我不知道为什么内部静态行为与公共静态不同.

我会将@pst标记为答案并添加注释以澄清问题,但@pst发表了评论,因此我无法将其标记为答案.

感谢您的输入.

  • `SHA1Managed.ComputeHash`是一个实例方法,而不是静态方法,所以你不能同时从多个线程安全地在同一个`SHA1Managed`实例上调用该方法."Hasher"是公开的还是内部的并不重要. (5认同)