I know that this question has been asked frequently on StackOverflow but my case is a bit different. I checked all the answers related to this issue and none solved my problem as in my case it only happens with browsers on mobile devices.
I only get the "Validation of ViewState MAC failed" error when posting back from a mobile browser that has been left open for some time. The error never appears when submitting a form from a computer browser. It neither appears when submitting from a mobile browser most of the time. It only appears when I open a mobile tab that was already submitted from some time and click the submit button again.
However, It happens all the time as well when I close my browser (so that it is not running in the mobile background), open it again and re-submit the form. I guess this is the main problem behind this error (re-launching the browser is causing page-reload on mobile before clicking on anything).
I tried the below solutions and none of them worked:
- Manually set MachineKey to my
web.config
- Use aspnet_regiis utility to run the managed application where machine keys will be persisted.
- Solutions proposed in this article
- set
LoadUserProfile = True
in the application pool - Set the
SessionTimeout = 0
in IIS application pool. - Secured my cookies over http.
Note: I know that setting enableViewStateMac="false"
in my web.config
will solve my problem, but I really don't wish to do so to avoid security depreciation in my application.
After a couple of tests, I noticed that the error only generates when the mobile browser force-reload/relaunch the page. For example, if I re-submit the form that has been already submitted from a mobile, most of the times it does not generate an error. However, sometimes, when I open the browser on the mobile, it force-reload/relaunches the page before I click on anything. Now when I click on the submit button, the error appears.
Possibly, this force-reload/relaunch is causing this error since the ViewState
is being altered.
Another possibility is that the mobile is expiring the sessions even though I've set the sessions to not expire in my IIS.
Yet, another possibility would be that the mobile does not allow the browser to run in the background resulting in force-reload to re-construct the page when the user opens the browser again.
I am using the below code in my application:
Partial Class MasterPage
Inherits System.Web.UI.MasterPage
Private Const AntiXsrfTokenKey As String = "__AntiXsrfToken"
Private Const AntiXsrfUserNameKey As String = "__AntiXsrfUserName"
Private _antiXsrfTokenValue As String
Protected Sub Page_Init(sender As Object, e As EventArgs)
' The code below helps to protect against XSRF attacks
Dim requestCookie = Request.Cookies(AntiXsrfTokenKey)
Dim requestCookieGuidValue As Guid
If requestCookie IsNot Nothing AndAlso Guid.TryParse(requestCookie.Value, requestCookieGuidValue) Then
' Use the Anti-XSRF token from the cookie
_antiXsrfTokenValue = requestCookie.Value
Page.ViewStateUserKey = _antiXsrfTokenValue
Else
' Generate a new Anti-XSRF token and save to the cookie
_antiXsrfTokenValue = Guid.NewGuid().ToString("N")
Page.ViewStateUserKey = _antiXsrfTokenValue
Dim responseCookie = New HttpCookie(AntiXsrfTokenKey) With {
.HttpOnly = True,
.Value = _antiXsrfTokenValue
}
If FormsAuthentication.RequireSSL AndAlso Request.IsSecureConnection Then
responseCookie.Secure = True
End If
Response.Cookies.[Set](responseCookie)
End If
AddHandler Page.PreLoad, AddressOf master_Page_PreLoad
End Sub
Protected Sub master_Page_PreLoad(sender As Object, e As EventArgs)
If Not IsPostBack Then
' Set Anti-XSRF token
ViewState(AntiXsrfTokenKey) = Page.ViewStateUserKey
ViewState(AntiXsrfUserNameKey) = If(Context.User.Identity.Name, [String].Empty)
Else
' Validate the Anti-XSRF token
If DirectCast(ViewState(AntiXsrfTokenKey), String) <> _antiXsrfTokenValue OrElse DirectCast(ViewState(AntiXsrfUserNameKey), String) <> (If(Context.User.Identity.Name, [String].Empty)) Then
Throw New InvalidOperationException("Validation of Anti-XSRF token failed.")
End If
End If
End Sub
Private Sub MasterPage_Load(sender As Object, e As EventArgs) Handles Me.Load
'Add Base Path and Canonical URL
Dim strBasePath = "<base href='" & AppSettings("LivePath") & "' />"
Page.Header.Controls.Add(New LiteralControl(strBasePath))
End Sub
End Class
I hope there is a solution to this since I don't want to end up setting enableViewStateMac="false"
in my web.config
[Update]
Potential Solution:
My current potential solution for this is to handle the "Validation of ViewState MAC failed" error and prompt a custom message to the user explaining the form validation failure. This way security and usability is balanced.
I was inspired by this article for this likely short-lived solution.