• ”Validation of viewstate MAC failed” 错误


    ”Validation of viewstate MAC failed” 错误

    在ASP.NET里面,View State使用较为广泛。它作为一个隐藏字段,可以帮助服务端”记住“客户端的改变,这样客户端 收到服务器对PostBack的响应后,仍然可以展现在PostBack之前设定的值 (具体参见http://msdn.microsoft.com/en-us/library/bb386448(v=vs.100).aspx )

    <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="..." />

    为了防止恶意客户端的PostBack里的ViewState被解读,ASP.NET会用消息验证码(MAC)来检查每个ViewState。可是一旦服务器无法正确解释正常客户端PostBack回来的ViewState时,整个应用都会停止工作。比如出现 ”Validation of viewstate MAC failed” 的错误。

    通常来说,一旦这样的错误出现,首先会考虑以下几种情况:

    1. 是不是有多台Web Server在负载均衡情况下运行。如果是的话,需要各台服务器使用相同的MAC进行ViewState的加密和解密工作。否则如果这个负载均衡环境没有完全做的Session Affinity,这种错误就会出现。

    2. 测试本机访问是否也有这种错误。如果是的话,除了尝试重新产生新的MachineKey (参见http://blogs.msdn.com/b/amb/archive/2012/07/31/easiest-way-to-generate-machinekey.aspx ),也可以用Process Monitor在复现问题的时候跟踪文件和注册表的访问,看看是不是因为W3WP.exe缺少权限而不能获取和MachineKey相关的信息。

    3. 在客户端和服务器端抓取网络包,比较ViewState是否被中间设备改动。这种情况不多见,但是也遇到过。算是复杂的一种情况。如果连接是SSL的,抓包没有办法查看,客户端就要使用Fiddler,而服务端需要采取额外诊断日志或者Debug的方法。

    4. 和具体代码相关,尤其是对ViewStateUserKey有特殊设置。

    这里谈到的是一个在一个大型的生产应用环境里遇到的实际问题,和上面的情况有关,但有些有趣的变化。

    这个环境里面有多台Web 服务器,采用了负载均衡方式。在客户试图登录时(login.aspx),总是会遇到”Validation of viewstate MAC failed”的错误。

    起初,怀疑是不同机器上WebAppication的MachineKey不一样引起的。检查了Web.Config里的配置,各个机器都是一样:

    复制代码
    <system.web>
    
    <machineKey decryptionKey="6284D74F8D9745C38712047622FFA047B02CA5C4049FB74E,IsolateApps" validationKey="137B974DC38A910D946AAF3ADF1D0386072170236F39C8165098035126FE7DFDF68C7BD3646052CE1769A47A45F098A65CEC3089523543370DD37830A5B2D13,IsolateApps" />
    
    </system.web>
    复制代码

    而且负载均衡也设置了Class C的Session Affinity

    后来发现这个问题即使本机访问也会出现。把应用程序池身份改为Admin后,问题同样。表明和权限无关。重新创建MachineKey,也没有变化。

    这时需要关注代码。获取了页面代码做Review. 在Login页面的Page_Init里面, 看到ViewStateUserKey

    protected void Page_Init(object sender, EventArgs e)
    {
            this.ViewStateUserKey = this.Session.SessionID;
     }

    表面上看这样的写法也没有什么问题。

    在IE上启用了Fiddler (连接是SSL) 后,发现客户端的PostBack里面没有Cookie的信息。这就是问题出现的直接原因:

    a. 在第一次访问Login页面时,用一个随机的SessionID A被嵌入了ViewState里面

    b. 在PostBack时,由于没有Cookie传回来(ASP.NET SessionID缺省存放在Cookie里),服务器就判断道客户端没有SessionID, 于是又使用一个新的SessionID B做ViewStateUserKey. 这样,从ViewState里面解出的是上次的SessionID A, 和新的不匹配。错误就出现了。

    可是客户端为什么不发送Cookie呢?

    原来这个服务器第一次回复时,对客户端的HTTP Header里面根本没有Set-Cookie字段。

    这是没有赋予Session 变量时ASP.NET的缺省行为 ( SessionID每次请求都会形成,但是未必会发送Set-Cookie 来让客户端保留这个SessioID,除非有赋予Session变量的行为)

    于是解决这个问题的直接方法就是在这个Page_Init里面第一时间加一个语句:

    protected void Page_Init(object sender, EventArgs e)
    {
        this.ViewStateUserKey = this.Session.SessionID;
        session("forViewSate")="value" 
    
     }

    这样服务器把SessionID在”Set-Cookie”里发送回去,客户端也可以用Cookie保留SessionID。问题就立刻解决了。

    更多参考:

    微软技术文章讨论如何处理” ”Validation of viewstate MAC failed”:

    http://support.microsoft.com/kb/2915218

     
     
    标签: .NETASP.NET
  • 相关阅读:
    策略模式
    装饰模式VS代理模式
    BufferedInputSream实现原理
    从字节码角度分析重载与重写
    函数sprintf真好用
    算法时间复杂度
    二项分布(Binomial Distribution)
    numpy中的tile函数
    图像缩放算法(最临近点插值算法、双线性内插值算法、双立方插值算法)
    C++ 类中成员函数的属性
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4134310.html
Copyright © 2020-2023  润新知