0

环境

好的,所以我尽量不在这里创建副本,但我意识到这个问题之前已经解决过。

我一直在对错误进行大量阅读:

视图状态 MAC 验证失败。如果此应用程序由 Web Farm 或集群托管,请确保配置指定相同的 validationKey 和验证算法。AutoGenerate 不能在集群中使用。

升级网络监控软件和 SQL 版本后,我开始收到错误消息。

该页面是显示它的站点外部的 ASP.NET 4.0 Web 表单,用 C# 编写,带有一些 JavaScript 和相当多的 SQL。它还大量使用 .NET 的图表形式(如图表上的六个图表区域,每个区域都有多个通过 SQL 动态生成的系列)。我们从 SQL Server 2008R2 的免费版本升级到完整 SQL Server 2012 实例的试用版,并将 SolarWinds Orion 版本更新到 NPM 10.6。

该代码是一个大型图表程序,用于跟踪我们每个网络平均的各种统计数据的健康状况。问题是,他们要求“滚动图表”,这意味着自动更新。我使用表单刷新而不是元或完整回发,因为有各种各样的变量允许图表停留在特定的统计数据、网络、页面和时间窗口上,这样当用户不理会它时,它将刷新并保留他们最初查看的视图。如果它不超过 5 分钟前,它将不断更新。所有这些值都存储在 ViewState 中。(最初,更糟糕的是,存储在页面上的隐藏文字中)。

更新软件并没有神奇地把它变成一个网络农场或集群,而且我们没有虚拟环境,尽管我们可能很快就会有。

这项研究

我知道问题是由于 ViewState 在不方便的时间刷新并导致密钥验证失败,因为页面加载与验证算法不同步。我见过很多类似的问题和答案,比如:

视图状态 MAC 的 ASP.NET 验证失败

在页面上停留 20 分钟以上时,视图状态 MAC 的验证失败

ScriptResource 错误:我被黑了吗?

http://aspadvice.com/blogs/joteke/archive/2006/02/02/15011.aspx

诚然,这不是面向客户的,而是根据 Microsoft:

即使应用程序或页面不使用视图状态,在生产网站中也不应将此属性设置为 false。视图状态 MAC 有助于确保除视图状态之外的其他 ASP.NET 功能的安全性。

我的问题:

所有这些答案似乎都有相同的解决方案,我不相信这些是好的解决方案。我有什么选择?从安全的角度来看,我的上司和我认为设置密钥并不好。我愿意调整代码以不同的方式存储东西。我不得不在其他地方使用会话状态,但我还是新手。在进行某种验证之前是否会遇到类似的刷新问题?我可以强制刷新运行得更慢吗?我还看到了一些关于更改密钥验证发生位置的内容。从安全的角度来看,该解决方案如何?

4

1 回答 1

0

首先,我终于能够找到我的错误。事实证明,我实际上是在设法创建一个 SQL Server 死锁,这反过来意味着我的 .Net 图表抛出了一个未处理的 NullReference 异常 (derp)。

好吧,所以,在 ASP.NET中只有几个ViewState 的替代品。我终于让我的页面正常工作了,所以我把这个留给任何偶然发生的人。

您在 SO 上看到的一种替代方法是设置机器密钥并启用 MAC 状态,如下所示:

<pages enableViewStateMac="true">

进而:

<machineKey 
  validationKey="[128 Hex Number]"
  decryptionKey="[64 Hex Number" 
  validation="SHA1" 
  decryption="AES" />

出于安全原因,我对此有所担心,但我无法使任何其他解决方案发挥作用。我最终得出的结论是,我只需静态设置它并根据微软的示例代码定期重新生成机器密钥:

    static void Main(string[] argv)
    {
        //128 Hex characters for the validation key, 64 for the AES decryption key
        int hexLengthForEncryption = 128;

        string validationKey = Generate_New_Key(hexLengthForEncryption, argv);

        hexLengthForEncryption = 64;

        string decryptionKey = Generate_New_Key(hexLengthForEncryption, argv);

        string[] originalKeys = new string[2] {validationKey, decryptionKey};

        Generate_File(originalKeys);

        Console.WriteLine("The file has been generated. Would you like to generate new keys in a new file?");

        string yorn = Console.ReadLine();

        while ((yorn != "N") && (yorn != "n") && (yorn != "no") && (yorn != "No"))
        {               
            hexLengthForEncryption = 128;
            validationKey = Generate_New_Key(hexLengthForEncryption, argv);
            hexLengthForEncryption = 64;
            decryptionKey = Generate_New_Key(hexLengthForEncryption, argv);

            string[] freshLines = new string[2]{validationKey, decryptionKey};

            Generate_File(freshLines);

            Console.WriteLine("The file has been generated. Would you like to generate new keys to a new file?");

            yorn = Console.ReadLine();
        }
    }

不过,这并没有完全解决我的问题。我最终做的是,对于有一个查找页面的图表,我在我的较大的 SQL 查询中添加了一个 try catch,尽管有类似这样的帖子的保留以及Stack Overflow 上的 WITH(NOLOCK) 的类似问题,我们还是决定可能的陷阱落在可接受的误差范围参数内。

在真正关心会话 ID 的页面中,我不得不强制程序暂时停止并返回查找页面。有趣的是,当我登出并且图表每两分钟刷新一次时,它根本没有崩溃。不使用 Session ID 的页面仍然在主页上设置了这样的一次性变量:

    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
        ViewStateUserKey = Session.SessionID;
    }

这在控制中使解决方案正常工作:

        //This variable is necessary to having a session state persist across postbacks, but is otherwise useless
        Session["Throwaway"] = DateTime.Now;

此页面上的 Catch 只是重定向回自身。带有搜索页面的页面导致了引用循环问题,因为会话状态(页面依赖于生成图表)是空的,因此破坏了图表。我不知道这会对任何人有所帮助,但是使用会话状态的图表和不需要会话状态的图表最终都在网络升级后工作。干杯!

于 2013-10-29T16:14:24.153 回答