異常描述:
Global.asax捕獲到異常:
System.Web.HttpException (0x80004005): 驗證視圖狀態 MAC 失敗。如果此應用程序由網絡場或群集承載,請確保 <machineKey> 配置指定了相同的 validationKey 和驗證算法。不能在群集中使用 AutoGenerate。 http://go.microsoft.com/fwlink/?LinkID=314055 ---> System.Web.UI.ViewStateException: 無效的視圖狀態。 Client IP: 10.0.0.172 Port: 52033 Referer: http://pcentertest.shenbianhui.cn/Test/WebForm1.aspx Path: /Test/WebForm2.aspx User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.101 Safari/537.36 ViewState: /wEPDwULLTE0MTM1MTM2MTRkZPqYgjmljF6+HgGibehV9ktjHcPeFSdh7aSGX+FPeAP/ 在 System.Web.UI.ViewStateException.ThrowMacValidationError(Exception inner, String persistedState) 在 System.Web.UI.ObjectStateFormatter.Deserialize(String inputString, Purpose purpose) 在 System.Web.UI.Util.DeserializeWithAssert(IStateFormatter2 formatter, String serializedState, Purpose purpose) 在 System.Web.UI.HiddenFieldPageStatePersister.Load() 在 System.Web.UI.Page.LoadPageStateFromPersistenceMedium() 在 System.Web.UI.Page.LoadAllState() 在 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) 在 System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) 在 System.Web.UI.Page.ProcessRequest() 在 System.Web.UI.Page.ProcessRequest(HttpContext context) 在 System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() 在 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
同一個站點內兩個頁面WebForm1.aspx和WebForm2.aspx。
WebForm1.aspx里是一個服務器表單控件,其form的action指向的是WebForm2.aspx。如下是WebForm1.aspx的html,WebForm2是一個空的表單。
<form id="form1" runat="server" action="WebForm2.aspx">
<asp:TextBox ID="txt1" runat="server"></asp:TextBox>
<asp:Button ID="btn1" runat="server" Text="submit"/>
</form>
本地測試是正常的。線上是nginx部署的,在提交表單時出現了上面的異常。 去年自打線上用了nginx后,這樣的異常就不斷來做客了。
訪問WebForm1時的網頁源代碼:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>
</title></head>
<body>
<form method="post" action="WebForm2.aspx" id="form1">
<div class="aspNetHidden">
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwULLTE0MTM1MTM2MTRkZPqYgjmljF6+HgGibehV9ktjHcPeFSdh7aSGX+FPeAP/" />
</div>
<div class="aspNetHidden">
<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="/wEdAAM2KkFwpZuLdd2aQa8ABSbJscfOVKgi+tKUa7rIRxwonUaz6Rs6w/mRtFpOGK59+RYCc553OHEnOJ0ehwkaFMWSNbUfXJpnRIAKLupf12VoZA==" />
</div>
<div>
<input name="txt1" type="text" id="txt1" />
<input type="submit" name="btn1" value="submit" id="btn1" />
</div>
</form>
</body>
</html>
網上查了一些資料。
有說是禁用viewstate是可以解決的。 這里,我新建了個WebForm1.html文件,然后,把WebForm1.aspx生成的html去掉asp.net生成的viewstate隱藏域后放到WebForm1.html里,這樣訪問WebForm1.html,是可以把form表單的數據提交到WebForm2.aspx的。
不過,不管怎么嘗試,當訪問WebForm1.aspx時,總是阻擋不了它生成viewstate隱藏域的腳步。
先把問題記錄下來。此后,還需再進一步處理。
ref:http://www.cnblogs.com/Setme/archive/2012/06/05/2537084.html
--------------------------------------------------------------后續20170426---------------------------------------------------------
今天項目上線,趁有些時間,就找運維着重解決一下這個頑固的問題。
運維在服務器主機上直接通過ip+端口的形式來訪問頁面,也同樣會出現這個異常。看來,我是誤認為與nginx有關了。
這里說明一下自己的大意,前幾天都是視圖從WebForm1上嘗試解決問題的,而現在仔細看了一下異常信息,異常是在WebForm2表單拋出來的。所以,要解決問題也得從WebForm2來入手。
參考的網頁說:一般而言是因為你的某些操作修改了視圖狀態,我猜測你可能使用了ajax並在客戶端用javascript動態添加了某些項。
而WebForm2是個空的表單,actually,即使去掉form空留一個<body></body>,也還是會報那個異常。
不過,按它說的,在WebForm2的@page里加了一個EnableViewStateMac="false",就不出現那個異常了。
問題是解決了,不過還是搞不明白,同樣的代碼,為什么測試環境沒問題,而生產上有這個異常呢? 運維同事也說可能是程序的漏洞,並不認為是服務器的問題。每個人都有護犢子的情節,當然解決問題要從客觀的角度來分析。
--------------------------------------------------------------后續20170426---------------------------------------------------------
接下來有必要了解一下EnableViewStateMac
EnableViewStateMac是asp.net內置的安全利器之一。
微軟官方對Page.EnableViewStateMac 屬性的定義:
Gets or sets a value indicating whether ASP.NET should check message authentication codes (MAC) in the page's view state when the page is posted back from the client.
什么意思呢?
需要先說一下大家熟知的ViewState:http請求本身是無狀態的,而視圖狀態則是用於在對同一個頁的兩個連續請求之間保持控件的狀態。
再來看看EnableViewState:
獲取或設置一個值,該值指示當前頁請求結束時該頁是否保持其視圖狀態以及它包含的任何服務器控件的視圖狀態。
如果該頁保持其視圖狀態,則為 true;否則為 false。默認為 true。
即使 EnableViewState 為 false,ASP.NET 用於檢測回發的頁中也可能呈現隱藏的視圖狀態字段。
好,接下來就可以介紹EnableViewStateMac了:
獲取或設置一個值,該值指示當頁從客戶端回發時,ASP.NET 是否應對頁的視圖狀態運行消息驗證檢查 (MAC)。
當 EnableViewStateMac 屬性設置為 true 時,將檢查編碼和加密的視圖狀態以驗證該視圖狀態在客戶端上是否未被篡改。 為了保證安全,asp.net默認設置EnableViewStateMac為true。
視圖狀態用於在對同一個頁的兩個連續請求之間保持控件的狀態。默認情況下,視圖狀態是 Base64 編碼的,並使用一個哈希值簽名,以防止篡改。除非更改默認的頁設置,否則不可能篡改視圖狀態。如果攻擊者修改了視圖狀態,甚至使用正確的算法重新生成了視圖狀態,ASP.NET 都會捕獲這些嘗試並引發異常。視圖狀態被篡改並不一定有害,雖然它修改了服務器控件的狀態 —— 但可能成為造成嚴重感染的工具。因此,不移除默認情況下進行的計算機身份驗證代碼 (MAC) 交叉檢查就非常重要。請參閱圖 2。
圖 2. 啟用 EnableViewStateMac 時,使視圖狀態本身難以篡改的因素
啟用了 MAC 檢查時(默認情況),將對序列化的視圖狀態附加一個哈希值,該值是使用某些服務器端值和視圖狀態用戶秘鑰(如果有)生成的。回發視圖狀態時,將使用新的服務器端值重新計算該哈希值,並將其與存儲的值進行比較。如果兩者匹配,則允許請求;否則將引發異常。即使假設黑客具有破解和重新生成視圖狀態的能力,他/她仍需要知道服務器存儲的值才可以得出有效的哈希。
ref:利用 ASP.NET 的內置功能抵御 Web 攻擊http://www.51cto.com/specbook/14/3232.htm
ref:驗證視圖狀態 MAC 失敗的處理辦法總結!http://blog.sina.com.cn/s/blog_3f42ab160100kv2v.html