由负载均衡策略不当引发的MAC错误

错误画面:

验证视图状态 MAC 失败。如果此应用程序由网络场或群集承载,请确保 <machineKey> 配置指定了相同的 validationKey 和验证算法。不能在群集中使用 AutoGenerate。
说明: 执行当前 Web 请求期间,出现未处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。

异常详细信息: System.Web.HttpException: 验证视图状态 MAC 失败。如果此应用程序由网络场或群集承载,请确保 <machineKey> 配置指定了相同的 validationKey 和验证算法。不能在群集中使用 AutoGenerate。

源错误:

执行当前 Web 请求期间生成了未处理的异常。可以使用下面的异常堆栈跟踪信息确定有关异常原因和发生位置的信息。 

堆栈跟踪:


[HttpException (0x80004005): 无法验证数据。]
   System.Web.Configuration.MachineKeySection.GetDecodedData(Byte[] buf, Byte[] modifier, Int32 start, Int32 length, Int32& dataLength) +294
   System.Web.UI.ObjectStateFormatter.Deserialize(String inputString) +203

[ViewStateException: 无效的视图状态。
 Client IP: 192.168.10.254
 Port: 27297
 User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
 ViewState: /wEPDwUJNjU0Mzc1ODc2ZBgBBR5fX0NvbnRyb2xzUmVxdWlyZVBvc3RCYWNrS2V5X18WAQUIZG93bkxvYWQ5a8feTBO0m3KiQzswy6eqF/oJBQ==
 Referer: http://10.10.1.74:12000/project/RedBillDownLoad/RedBillDownLoad.aspx Path: /project/RedBillDownLoad/RedBillDownLoad.aspx]

[HttpException (0x80004005): 验证视图状态 MAC 失败。如果此应用程序由网络场或群集承载,请确保 <machineKey> 配置指定了相同的 validationKey 和验证算法。不能在群集中使用 AutoGenerate。]
   System.Web.UI.ViewStateException.ThrowError(Exception inner, String persistedState, String errorPageMessage, Boolean macValidationError) +267
   System.Web.UI.ObjectStateFormatter.Deserialize(String inputString) +282
   System.Web.UI.ObjectStateFormatter.System.Web.UI.IStateFormatter.Deserialize(String serializedState) +4
   System.Web.UI.Util.DeserializeWithAssert(IStateFormatter formatter, String serializedState) +37
   System.Web.UI.HiddenFieldPageStatePersister.Load() +198
   System.Web.UI.Page.LoadPageStateFromPersistenceMedium() +83
   System.Web.UI.Page.LoadAllState() +35
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +7350
   System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +213
   System.Web.UI.Page.ProcessRequest() +86
   System.Web.UI.Page.ProcessRequestWithNoAssert(HttpContext context) +18
   System.Web.UI.Page.ProcessRequest(HttpContext context) +49
   ASP.project_redbilldownload_redbilldownload_aspx.ProcessRequest(HttpContext context) +4
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +358
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +64

 


--------------------------------------------------------------------------------
版本信息: Microsoft .NET Framework 版本:2.0.50727.1433; ASP.NET 版本:2.0.50727.1433
2、错误分析
当浏览器向负载均衡发出请求,负载均衡根据配置策略将请求发送给其后的一台机器,该机器响应后将返回信息发给负载均衡,负载均衡再发给客户端,问题就发生在这里,如果不是配置单一IP访问策略,当用户在第二次请求页面回发时,会导致视图状态验证不通过。

3、解决方案
在网上有两种方案:

解决方案(1)

处理页面增加

<%@ Page Language="C#"  enableViewStateMac="false" %>

    <pages enableViewStateMac="false"></pages>

其它不需要

如果不再遇到视图状态错误, 问题是否与 MAC 功能。 要点 仅关闭视图状态 MAC 功能以帮助诊断问题。 不应将视图状态 MAC 关闭要解决问题。 如果这样, 则可能引入安全漏洞。 有关详细信息, 请访问以下 MSDN 网站:

http://msdn2.microsoft.com/en-us/library/aa302388.aspx (http://msdn2.microsoft.com/en-us/library/aa302388.aspx)
如果, 关闭视图状态 MAC 功能并使用您对于执行不 HTML 控件视图状态编码 (例如, Label 控件), 攻击者可查看状态数据篡改并可放置任意数据以视图状态。 此任意数据解码和它们显示投递页面时再使用由控件。 因此, 攻击可注入到应用程序除非您工作以防止攻击脚本。 例如, 攻击者可能解码数据、 入然后和 Label 控件是, 数据链接插入到脚本从 Web 站点。 任何用户单击链接上应受害者的脚本注入攻击, 可能潜在窃取其身份验证 Cookie 或会话 ID。 脚本还可能让攻击改变控件使用视图状态状态数据和应用程序特定攻击可能发生作为结果。 一般, Microsoft 建议, 您视图状态 MAC 功能除非您是完全相信有对于执行不 HTML 所有控件或者禁用视图状态不关闭编码其输出 (例如, DataGrid 控件、 DataList 控件、 Label 控件和其他控件) 或, 根据每个请求成知会是安全始终明确设置值。 有关详细信息, 请单击下列文章编号, 查看 Microsoft 知识库文章中文章:

316920 (http://support.microsoft.com/kb/316920/) 使用 Server.Transfer 方法时收到 " 视图状态无效 " 错误信息
324488 (http://support.microsoft.com/kb/324488/) 表单身份验证和视图状态负载间歇性失败
enableViewStateMac="false"

官方网站

http://support.microsoft.com/kb/829743/zh-cn

==========================================

解决方案(2)推荐,测试不成功,暂不知原因

如果你的Asp.Net程序执行时碰到这种错误:“验证视图状态 MAC 失败。如果此应用程序由网络场或群集承载,请确保  <machineKey> 配置指定了相同的 validationKey 和验证算法。不能在群集中使用 AutoGenerate。”那么说明你没有让你的应用程序使用统一的machineKey,那么machineKey的作用是什么呢?按照MSDN的标准说法:“对密钥进行配置,以便将其用于对 Forms 身份验证 Cookie 数据和视图状态数据进行加密和解密,并将其用于对进程外会话状态标识进行验证。”也就是说Asp.Net的很多加密,都是依赖于machineKey里面的值,例如Forms 身份验证 Cookie、ViewState的加密。默认情况下,Asp.Net的配置是自己动态生成,如果单台服务器当然没问题,但是如果多台服务器负载均衡,machineKey还采用动态生成的方式,每台服务器上的machinekey值不一致,就导致加密出来的结果也不一致,不能共享验证和ViewState,所以对于多台服务器负载均衡的情况,一定要在每台站点配置相同的machineKey。  machineKey生成的算法:  validationKey = CreateKey(20);  decryptionKey = CreateKey(24);      protected string CreateKey(int len)      {              byte[] bytes = new byte[len];              new RNGCryptoServiceProvider().GetBytes(bytes);                StringBuilder sb = new StringBuilder();                for(int i = 0; i  < bytes.Length; i++)                {                      sb.Append(string.Format("{0:X2}",bytes[i]));                }                return sb.ToString();      }  附参考的matchineKey配置:  <?xml version="1.0"?>  <configuration>    <system.web>      <machineKey validationKey="3FF1E929BC0534950B0920A7B59FA698BD02DFE8" decryptionKey="280450BB36319B474C996B506A95AEDF9B51211B1D2B7A77" decryption="3DES" validation="SHA1"/>        </system.web>  </configuration> 你写一个页面来调用这个生成machineKey的函数,然后再每台服务器上运行这个页面看看这个值是什么,然后在根据这个值来配置各个服务器

========================

产生MAC

http://www.aspxboy.com/mk/default.aspx

<machineKey validationKey="B8CEF0C74E23E7197FCC4C9E3617C0007D94D43C7F7A79C582C54B95D69B946DFD49CAF5AA72F9A8CA2CBA040A9DF64DC1DF90DAE1214AE4F1AB7FA56DD65C0D" decryptionKey="D7F1CE31847C4FB31EF51E14F3820D52B659AF8523FC932C03506CC075DB8B28" validation="SHA1" decryption="AES" />

 

解决方案(3)
更改负载均衡策略,单一IP服务器模式。

解决方案(4)

最近购买了一个NET2.0的虚拟主机,开开心心的把刚做好的网站传了上去,运行后却出了一个令人十分头痛的问题, cookies莫名其妙的提前过期,部分页面不定时的出现MAC验证失败,可是程序在本地运行一切正常啊,于是怀疑服务器设置有问题,在与虚拟主机提供商几次电话之后(都快吵起来了)他们决定给我重新更换一台服务器,换完之后,上传程序,问题依旧,与此同时我也可以确定,我的程序绝对是没有问题的,后来上网一搜,有很多讲MAC验证视图状态失败的解决方法都是在页里或web.config里加EnableEventValidation="false" EnableViewStateMac="false" ViewStateEncryptionMode="Never" 这些个设置以避免错误出现,我也尝试了一下,并不能从根本上解决我遇到的问题。

  就在我快要绝望的时候无意间发现了一个网页里讲他的Blog系统从NET1.1升级到NET2后之前所生成的所有cookies将会失效,因为NET2和NET1 使用的machineKey不相同,真是柳暗花明又一村啊,顺着这个线索我又查阅了很多关于machineKey的资料,其中有一篇文章讲的非常好:
----------------------------------------------------------------------------------
验证视图状态 MAC 失败。如果此应用程序由网络场或群集承载,请确保 <machineKey> 配置指定了相同的 validationKey 和验证算法。不能在群集中使用 AutoGenerate。

Asp.Net应用程序中为什么要MachineKey?如何生成MachineKey?2007年01月24日 星期三 15:03如果你的Asp.Net程序执行时碰到这种错误:“验证视图状态 MAC 失败。如果此应用程序由网络场或群集承载,请确保 <machineKey> 配置指定了相同的 validationKey 和验证算法。不能在群集中使用 AutoGenerate。”那么说明你没有让你的应用程序使用统一的machineKey,那么machineKey的作用是什么呢?按照MSDN的标准说法:“对密钥进行配置,以便将其用于对 Forms 身份验证 Cookie 数据和视图状态数据进行加密和解密,并将其用于对进程外会话状态标识进行验证。”也就是说Asp.Net的很多加密,都是依赖于machineKey里面的值,例如Forms 身份验证 Cookie、ViewState的加密。默认情况下,Asp.Net的配置是自己动态生成,如果单台服务器当然没问题,但是如果多台服务器负载均衡, machineKey还采用动态生成的方式,每台服务器上的machinekey值不一致,就导致加密出来的结果也不一致,不能共享验证和 ViewState,所以对于多台服务器负载均衡的情况,一定要在每台站点配置相同的machineKey。
------------------------------------------------------------------------------------
查下MSDN就明白了,validationKey和decryptionKey的默认值是AutoGenerate,由系统随机生成密钥,如果在本地或者使用的是独立主机通常不会有什么问题,但是使用虚拟主机,一台服务器上有多个虚拟主机存在时就会出现以上问题,MSDN中也特别指出不能在群集中使用 AutoGenerate应该指定固定的密钥值,至此真相水落石出,立刻在web.config中添加关于machineKey的配置项,并手动设置其中的密钥值,这里请注意,不同加密算法对于密钥的最大字符长度是不同的,在这里能够使用的有AES,DES,3DES,SHA1,MD5,我只知道DES的密钥字符长度为16,3DES长度为48,手动设置时密钥长度必须等于其最大长度,否则会出错!至于密钥的16进制值可以随便输入。

参考的matchineKey配置:

  <system.web>
    <machineKey validation="3DES" validationKey="319B474B1D2B7A87C996B280450BB36506A95AEDF9B51211" decryptionKey="280450BB36319B474C996B506A95AEDF9B51211B1D2B7A87" decryption="3DES"/>
     </system.web>

 

 

posted @ 2009-08-26 17:16  design-life  阅读(487)  评论(0编辑  收藏  举报