案例分析:无效的viewstate[翻译]

来源:互联网 发布:手机屏幕锁解锁软件 编辑:程序博客网 时间:2024/06/05 04:41
案例分析:无效的viewstate

上个礼拜帮同事解决一个关于viewstate的案例,很有意思..

场景

客户收到类似下面的的事件日志:

Event Type: Information
Event Source: ASP.NET 2.0.50727.0
Event Category: Web Event
Event ID: 1316
Date: 2007-06-11
Time: 09:48:02
User: N/A
Computer: MYMACHINE

描述:

Event code: 4009
Event message: Viewstate verification failed. Reason: The viewstate supplied failed integrity check.
Event time: 2007-06-11 09:48:02
Event time (UTC): 2007-06-11 07:48:02
Event ID: 14cc57c05e834de98c7df506a013a706
Event sequence: 10
Event occurrence: 1
Event detail code: 50203

应用程序信息:

Application domain: /LM/w3svc/1/root/MyApp-3-128260216693527710
Trust level: Full
Application Virtual Path: /MyApp
Application Path: c:/inetpub/wwwroot/MyApp/
Machine name: MYMACHINE

进程信息:

Process ID: 3640
Process name: w3wp.exe
Account name: NT AUTHORITY/NETWORK SERVICE
Request information:
Request URL: http://mymachine/MyApp/MyWebForm.aspx
Request path: /TestBadViewstate/WebForm1.aspx
User host address: 127.0.0.1
User:
Is authenticated: False
Authentication Type:
Thread account name: NT AUTHORITY/NETWORK SERVICE

ViewStateException information:

Exception message: Invalid viewstate.
Client IP: 127.0.0.1
Port: 14644
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; WOW64; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.0.04324.17; InfoPath.2)
PersistedState:
dDwxOTM2NzUxODMzO3Q8O2w8aTwxPjs+O2w8dDw7bDxpPDE+Oz47bDx0PHA8bDxfX0hlYWRpbmc7PjtsPENvdXJzZSBTZWFyY2g7Pj47bDxpPDE+Oz47bDx0PDtsPGk8MT47aTwzPjs+O2w...
Referer: http://SomeThirdPartySite.com/SomePage.htm
Path: /MyApp/MyWebForm.aspx

Custom event details:

For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.

调用堆栈:

[HttpException (0x80004005): Validation of viewstate MAC failed. If this application is hosted by a Web Farm or cluster, ensure that <machineKey>
configuration specifies the same validationKey and validation algorithm. AutoGenerate cannot be used in a cluster.]

 

System.Web.UI.ViewStateException.ThrowError(Exception inner, String persistedState, String errorPageMessage, Boolean macValidationError) +119
System.Web.UI.ObjectStateFormatter.Deserialize(String inputString) +252
System.Web.UI.ObjectStateFormatter.System.Web.UI.IStateFormatter.Deserialize(String serializedState) +5
System.Web.UI.Util.DeserializeWithAssert(IStateFormatter formatter, String serializedState) +37
System.Web.UI.HiddenFieldPageStatePersister.Load() +222
System.Web.UI.Page.LoadPageStateFromPersistenceMedium() +80
System.Web.UI.Page.LoadAllState() +35
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +9041
System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +217
System.Web.UI.Page.ProcessRequest() +85
System.Web.UI.Page.ProcessRequestWithNoAssert(HttpContext context) +20
System.Web.UI.Page.ProcessRequest(HttpContext context) +110
ASP.MyPage_aspx.ProcessRequest(HttpContext context) +30
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +405
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +65

排错

如果viewstate错误发生在.net 1.1中并且没有收到类似上面的事件,请确保安装了sp1或者http://support.microsoft.com/?id=831150 之后的版本,这个补丁引入了对上述事件的日志,对于绝大多数viewstate错误的排除至关重要.

众所周知,viewstate是一个以base64编码,包含webform控件状态信息的字符串,为避免viewstate被篡改,会利用machine key,pagename等来对其加以验证。如果字符串被破坏或者由于某种原因无法使用base64解码,将不能通过验证,同时收到类似前面描述的错误。

典型的viewstate错误原因如下:

1 运行了webfarm,并且所有节点的machine keys不一致

2 运行了webfarm,并且某台节点上的出错页面与其他节点的页面有些许初入,比如:一个接点已经升级到2.0但其他接点仍然是1.1,或者页面使用的某些控件的生成不一致。

更全面的列表,请访问: http://support.microsoft.com/?id=829743

在这个案例中,客户仅仅从.net 1.1升级到.net 2.0,没有运行webfarm。错误仅在两个特定页面间歇发生,绝大部分时间运行得都很好。

在非webfarm环境下,这种问题非常罕见,特别是间歇性出错,非常古怪。我曾经见过使用移动客户端,viewstate非常大,而某些移动设备仅发送x kb数据导致viewstate不能全部发送的情况。但现在客户端是IE7.0,这就有点麻烦了…

我用Fritz Onion写的viewstatedecoder 来解码viewstate以确保它没有被破坏,看起来是非常标准的textbox等内容。

运气不错

我很幸运,客户也一样。我见过不计其数的viewstate,知道viewstate应该是什么样的,当我看到另一条事件日志时我注意到持久状态以dDw打头。对绝大部分人而言可能没什么意义但我知道2.0的viewstate应该以/wE打头…  事实上在相关页面html源码中查看viewstate隐藏域内容时,发现的确是通常的2.0 viewstate,除了dDw... 典型的1.1 viewstate.

现在的问题是,这些1.1 viewstate是从哪儿来的? 跳到前面,你可能会注意到当前有一个指向htm页面的引用:http://somethirdpartysite.com/SomePage.htm ,换句话说,站点本身并没有问题,问题在于第三方站点发送1.1的viewstate到这个页面,显然在2.0下无法通过验证。

检查第三方站点的htm页面源码,能看到之前所怀疑到的.. 页面包含一个带有隐藏viewstate的form,并且数据post到我们的aspx页面。

技术上来讲,除了aspx自身之外,任何其他页面都不能发送post请求到aspx页面,所以,如果post到aspx页面的引用不是指向页面本身,就不是好事,为了抵御这类事情,就有了viewstate验证。但显然这让除错工作变得令人头疼。

结论:

这个案例的解决办法就是到第三方站点,让对方知道站点已经升级并请他们避免post数据到你的站点,更好的方式是链接或者重定向到站点.

如果第三方站点能够使用私有格式发送和接受数据,那么web服务将是一个非常好的解决办法。


原文地址:http://blogs.msdn.com/tess/archive/2007/06/11/a-case-of-invalid-viewstate.aspx

翻译:shalen520   [水平有限,请多指教]

版权归原文作者所有,转载请注明出处


附:原文

A Case of Invalid Viewstate

Last week I was helping a colleague of mine with a viewstate case that turned out to be pretty interesting...

Scenario

The customer was getting events similar to the following in the eventlog and needed to know why they occurred

Event Type: Information
Event Source: ASP.NET 2.0.50727.0
Event Category: Web Event
Event ID: 1316
Date: 2007-06-11
Time: 09:48:02
User: N/A
Computer: MYMACHINE

Description:

 

Event code: 4009
Event message: Viewstate verification failed. Reason: The viewstate supplied failed integrity check.
Event time: 2007-06-11 09:48:02
Event time (UTC): 2007-06-11 07:48:02
Event ID: 14cc57c05e834de98c7df506a013a706
Event sequence: 10
Event occurrence: 1
Event detail code: 50203

 

Application information:

 

 

Application domain: /LM/w3svc/1/root/MyApp-3-128260216693527710
Trust level: Full
Application Virtual Path: /MyApp
Application Path: c:/inetpub/wwwroot/MyApp/
Machine name: MYMACHINE

 

Process information:

 

 

Process ID: 3640
Process name: w3wp.exe
Account name: NT AUTHORITY/NETWORK SERVICE
Request information:
Request URL: http://mymachine/MyApp/MyWebForm.aspx
Request path: /TestBadViewstate/WebForm1.aspx
User host address: 127.0.0.1
User:
Is authenticated: False
Authentication Type:
Thread account name: NT AUTHORITY/NETWORK SERVICE

 

ViewStateException information:

 

 

Exception message: Invalid viewstate.
Client IP: 127.0.0.1
Port: 14644
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; WOW64; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.0.04324.17; InfoPath.2)
PersistedState:
dDwxOTM2NzUxODMzO3Q8O2w8aTwxPjs+O2w8dDw7bDxpPDE+Oz47bDx0PHA8bDxfX0hlYWRpbmc7PjtsPENvdXJzZSBTZWFyY2g7Pj47bDxpPDE+Oz47bDx0PDtsPGk8MT47aTwzPjs+O2w...
Referer: http://SomeThirdPartySite.com/SomePage.htm
Path: /MyApp/MyWebForm.aspx

 

Custom event details:

For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.

 

 

And the callstack reported was:

[HttpException (0x80004005): Validation of viewstate MAC failed. If this application is hosted by a Web Farm or cluster, ensure that <machineKey>
configuration specifies the same validationKey and validation algorithm. AutoGenerate cannot be used in a cluster.]

 

System.Web.UI.ViewStateException.ThrowError(Exception inner, String persistedState, String errorPageMessage, Boolean macValidationError) +119
System.Web.UI.ObjectStateFormatter.Deserialize(String inputString) +252
System.Web.UI.ObjectStateFormatter.System.Web.UI.IStateFormatter.Deserialize(String serializedState) +5
System.Web.UI.Util.DeserializeWithAssert(IStateFormatter formatter, String serializedState) +37
System.Web.UI.HiddenFieldPageStatePersister.Load() +222
System.Web.UI.Page.LoadPageStateFromPersistenceMedium() +80
System.Web.UI.Page.LoadAllState() +35
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +9041
System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +217
System.Web.UI.Page.ProcessRequest() +85
System.Web.UI.Page.ProcessRequestWithNoAssert(HttpContext context) +20
System.Web.UI.Page.ProcessRequest(HttpContext context) +110
ASP.MyPage_aspx.ProcessRequest(HttpContext context) +30
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +405
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +65

 

 

Troubleshooting

If you get viewstate errors on 1.1. and dont get events like the above, make sure that you have SP1 installed or at least a version of 1.1 later than http://support.microsoft.com/?id=831150  since this hotfix introduced the type of logging above, which is crucial to troubleshooting most viewstate errors.

Viewstate, as most of you know, is a Base64 encoded string containing information about the state of the controls on the webform.  To avoid tampering the viewstate is validated against the machine key, pagename etc. and if the string is either corrupt in some way such that it cant be Base64 decoded or such that it doesn't pass validation you will get an error like the above.

Typically viewstate errors will occur if

  • You're on a web farm and the machine keys are not consistent on all nodes
  • You're on a web farm and the page is slightly different on one node than ot the others, for example if one node is upgraded to 2.0 and the other is still 1.1 or if some controls used on the page are built differently

For a more comprehensive list see: http://support.microsoft.com/?id=829743

 

In this particular case they had just upgraded to 2.0 from 1.1, they were not running on a web farm.  The error occurred intermittently and only on two specific pages, but most of the time these pages were served just fine without viewstate errors.

Since it is very unusual for errors like this to occur in a non-web farm scenario, especially intermittently, this issue was very curious.   I have seen that happen sometimes when the client was a mobile device and the viewstate was very large as some mobile devices will only send x kb of data so the issue there would be that the viewstate was corrupted because not all the viewstate was sent.   In this case the client was IE 7.0 so no such luck...

I used Fritz Onion's viewstatedecoderr to decode the viewstate to verify that it wasn't corrupted and sure enough the viewstate was just fine, the contents seemed to be fairly standard textboxes etc.

Lucky break

Lucky for me, and for them:)  I have seen enough encoded viewstate to know what viewstate is supposed to look like, so when i took another look at the eventlog entry i noticed that the persisted state started with dDw...    to most people this probably just looks like mumbojumbo but I happen to know that viewstate on 2.0 is supposed to start with /wE...  in fact when I browsed their site on the internet I could indeed see that the typical viewstate for these affected pages (from the hidden viewstate field in view source) was perfectly normal 2.0 viewstate while the dDw... that was sent to the page is typical for 1.1 viewstate.

Knowing this, the question is now, where does this 1.1. viewstate come from?   This is where the eventlog entry comes in handy again... and if you have jumped ahead a bit you have probably noticed by now that the referer is a htm page http://somethirdpartysite.com/SomePage.htm, in other words. there is nothing wrong with the site itself, the problem is that somehow this 3rd party site is posting 1.1. viewstate to the page, and of course that won't validate well against the new 2.0 page.

Browsing to the 3rd party site and looking at the source for the htm file we can see what we already suspected... the page contains a form, with a hidden viewstate field and the post action for the form is our aspx page, so this 3rd party site apparently did a bit of a hack, copying the viewstate while this site was still 1.1. and posting that viewstate to the form... 

Technically, noone but the aspx page itself should really be allowed to post to the aspx page, so anytime the referer of a post to the aspx page is someone other than itself that is bad, and again, to guard against things like this the viewstate validation exists, but of course it might prove to cause a bit of a troubleshooting headache for you.

 

Conclusion

The solution in this case was to talk to the 3rd party site, let them know about the upgrade and ask them to avoid posting to the site but rather link to the site or redirect to it since there is no way of knowing how long viewstate will be valid as it can change with any type of upgrade to the page.

If there is a benefit to having the 3rd party site being able to post data and show the results in their proprietary format, a web service would be a pretty good solution.