验证视图状态 MAC 的安全解决方案失败

本文关键字:解决方案 失败 安全 视图状态 MAC 验证 | 更新日期: 2023-09-27 18:35:39

环境

好的,所以我尽量不在这里创建重复项,但我意识到这个问题以前已经解决了。

我一直在阅读有关该错误的内容:

视图状态 MAC 验证失败。如果此应用程序由 Web 场或群集承载,请确保配置指定相同的验证密钥和验证算法。自动生成不能在群集中使用。

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

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

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

更新软件并没有神奇地将其变成 Web 场或群集,我们也没有虚拟环境,尽管我们可能很快就会。

研究

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

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

视图状态 MAC 在页面上 20+ 分钟时验证失败

脚本资源错误:我是否被黑客入侵?

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

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

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

我的问题:

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

验证视图状态 MAC 的安全解决方案失败

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

好的,所以,ASP.NET 中只有几种视图状态的替代方案。我终于让我的页面正常工作了,所以我把它留在这里给任何随机遇到它的人。

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

<pages enableViewStateMac="true">

然后:

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

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

    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查询中添加了一个尝试捕获,尽管像这样的帖子保留了类似的担忧,并且对堆栈溢出上的WITH(NOLOCK)存在类似问题,但我们决定可能的陷阱落在可接受的误差范围参数范围内。

在实际关心会话ID的页面中,我不得不强制程序短暂停止并返回查找页面。有趣的是,当我注销并且图表在一夜之间每两分钟刷新一次时,它根本没有崩溃。不使用会话 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 只是重定向回自身。带有搜索页面的那个导致了引用循环问题,因为会话状态(页面依赖于它来生成图表)为空,因此破坏了图表。我不知道这会对任何人有所帮助,但是使用会话状态的图表和不需要会话状态的图表在网络升级后终于可以工作了。干杯!