locked
Does Anti XSRF Tokens or Session ID affects ViewState validation? RRS feed

  • Question

  • User-924931093 posted

    I built a site that's running on a two load-balanced servers (web-farm), after a while I had to do the following:

    at the login page, when the user enters user-name and pass, if the user is valid then I'm abandoning the session and creating a new one as follows:

    protected void btnLogin_Click(object sender, EventArgs e)
            {
                var Token = Guid.Empty;
                try
                {
                    if (IsValidCaptcha())
                    {
                        string email = txtEmail.Text.Trim();
                        string pw = txtPassword.Text.Trim();                      
                        AbandonSession();//Delete any existing sessions
                        var newSessionId = CreateSessionId(HttpContext.Current); //Create a new SessionId
                        SetSessionId(HttpContext.Current, newSessionId);
                        Token = SecureLogin.Login(email, pw, LangCode);
                    }
                    else
                    {
                        lblMsg.Style.Add("display", "block");
                    }
                }
                catch (Exception)
                {
                    Token = Guid.Empty;
                    lblMsg.Style.Add("display", "block");
                }
                if (Token != Guid.Empty)
                {
                    Response.Redirect($"HiddenPage.aspx?token={Token.ToString()}", false);
                }
                else
                {
                    lblMsg.Style.Add("display", "block");
                }
            }
    
    protected void AbandonSession()
            {
                Session.Clear();
                Session.Abandon();
                Session.RemoveAll();
                if (Request.Cookies["ASP.NET_SessionId"] != null)
                {
                    Response.Cookies["ASP.NET_SessionId"].Value = string.Empty;
                    Response.Cookies["ASP.NET_SessionId"].Expires = DateTime.Now.AddMonths(-20);
                }
                if (Request.Cookies["__AntiXsrfToken"] != null)
                {
                    Response.Cookies["__AntiXsrfToken"].Value = string.Empty;
                    Response.Cookies["__AntiXsrfToken"].Expires = DateTime.Now.AddMonths(-20);
                }
            }
    
            private string CreateSessionId(HttpContext httpContext)
            {
                var manager = new SessionIDManager();
    
                string newSessionId = manager.CreateSessionID(httpContext);
    
                return newSessionId;
            }
    
            public void SetSessionId(HttpContext httpContext, string newSessionId)
            {
                try
                {
                    var manager = new SessionIDManager();
    
                    manager.SaveSessionID(httpContext, newSessionId, out bool redirected, out bool cookieAdded);
                }
                catch(Exception ex)
                {
                    SmtpMailer.SendMsg(ex.Message + ex.StackTrace + ex.InnerException, "", "");
                }
    
            }

    This is one of the requirements for the site and I can't change it at all (changing the session after login to the site).

    after applying this approach, I started getting this error almost in every page in the site (every now and then).

    Event code: 4009  
            Event message: Viewstate verification failed. 
            Reason: The viewstate supplied failed integrity check.  
            Event time: 1/22/2019 2:53:36 PM  
            Event time (UTC): 1/22/2019 7:53:36 PM  
            Event ID: 5ffacfa116224c9f8f516ead8a89cc55  
            Event sequence: 378  
            Event occurrence: 1  
            Event detail code: 50203    
            Application information: 
            Application domain: /LM/W3SVC/2/ROOT-1-131926597583461452 
            Trust level: Full 
            Application Virtual Path: / 
            Application Path: ........... 
            Machine name: ..............    Process information: 
            Process ID: 6624 
            Process name: w3wp.exe 
            Account name: IIS APPPOOL\..............    Request information: 
            Request URL: ............../qConsole/CampaignGroup-Launch.aspx
            Request path: /qConsole/CampaignGroup-Launch.aspx 
            User host address: .............. 
            User:  
            Is authenticated: False 
            Authentication Type:  
            Thread account name: IIS APPPOOL\..............

    I double checked (a) the machine key /decryption key is the same on both servers in load balancing, and (b) that they are not set to auto generate

    and also I added this code to Global.asax

    protected void Session_Start(object sender, EventArgs e)
            {
                Session.Timeout = 60;
            }

    and I have this set in the web.config file

    <sessionState timeout="25" />

    Important Note: I'm using anti xsrf tokens in the Master Page to protect against xsrf, and it's using ViewState variables as following:

    protected void Page_Init(object sender, EventArgs e)
        {
            if (Session["CurrentUser"== null)
            {
                Response.Redirect("/");
            }
            
            //protect against XSRF attacks
            var requestCookie = Request.Cookies[AntiXsrfTokenKey];
            Guid requestCookieGuidValue;
            if (requestCookie != null && Guid.TryParse(requestCookie.Value, out requestCookieGuidValue))
            {
                // 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 = GenNewId();
                Page.ViewStateUserKey = _antiXsrfTokenValue;
     
                var responseCookie = new HttpCookie(AntiXsrfTokenKey)
                {
                    HttpOnly = true,
                    Value = _antiXsrfTokenValue,
                    Expires = DateTime.Now.AddMinutes(10.0)
                };
                if (FormsAuthentication.RequireSSL && Request.IsSecureConnection)
                {
                    responseCookie.Secure = true;
                }
                Response.Cookies.Set(responseCookie);
            }
            
            Page.PreLoad += master_Page_PreLoad;
        }


    Here where I'm getting the error and being redirected to the Error page:

    protected void master_Page_PreLoad(object sender, EventArgs e)
            {
                try
                {
                    if (!IsPostBack)
                    {
                        // Set Anti-XSRF token
                        ViewState[AntiXsrfTokenKey] = Page.ViewStateUserKey;
                        ViewState[AntiXsrfUserNameKey] = Session.SessionID.ToString();
                    }
                    else
                    {
                        // Validate the Anti-XSRF token
                        if ((string)ViewState[AntiXsrfTokenKey] != _antiXsrfTokenValue
                            || (string)ViewState[AntiXsrfUserNameKey] != Session.SessionID)
                        {                        
                            Response.Redirect("/Error");
                        }
                    }
                }
                catch (Exception ex)
                {
                    SmtpMailer.SendMsg(ex.Message + ex.Source + ex.StackTrace);
                }
            }

    I have a feeling that the issue I'm having revolves around the feature I added (creating new session-id after the login page), any ideas or thoughts are really appreciated.

    Thanks

    Thursday, January 24, 2019 4:03 PM

Answers

  • User475983607 posted

    Session, XSRF tokens, and ViewState are all affected by load balancing.  Especially InProc session, since Session exists in memory on the server that created the Session.  The antiforgery tokens and  ViewState are encrypted by a web server and set to the browser using cookies and input fields.  The load balanced servers must share the same machine key and scheme used to encrypt the data otherwise the servers cannot decrypt antiforgery tokens created on the other server.

    Also the error message can happen if a user times out.   

    Is authenticated: False 

    Or JavaScript is used to update a control on the page like a dropdownlist.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, January 24, 2019 4:15 PM
  • User-893317190 posted

    Hi basel@Simboliq,

    You could refer to the link below for similar solution for csrf token.

    https://stackoverflow.com/questions/1418233/setting-viewstateuserkey-gives-me-a-validation-of-viewstate-mac-failed-error

    If you still have problem, please debug the code in your local machine to see whether it works.

    Best regards,

    Ackerly Xu

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, January 31, 2019 5:36 AM

All replies

  • User475983607 posted

    Session, XSRF tokens, and ViewState are all affected by load balancing.  Especially InProc session, since Session exists in memory on the server that created the Session.  The antiforgery tokens and  ViewState are encrypted by a web server and set to the browser using cookies and input fields.  The load balanced servers must share the same machine key and scheme used to encrypt the data otherwise the servers cannot decrypt antiforgery tokens created on the other server.

    Also the error message can happen if a user times out.   

    Is authenticated: False 

    Or JavaScript is used to update a control on the page like a dropdownlist.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, January 24, 2019 4:15 PM
  • User-924931093 posted

    Thanks for the reply, I double checked that they share the same machine key and scheme used to encrypt the data, using the IIS Console -> Machine key section and they're identical.

    is this what you mean? or there's somewhere else to check?

    Thursday, January 24, 2019 4:21 PM
  • User-924931093 posted

    Also the error message can happen if a user times out.   

    Is authenticated: False 

    what do you mean by this?

    Thursday, January 24, 2019 4:23 PM
  • User475983607 posted

    This error...

    Event message: Viewstate verification failed. 

    ...can also happen if JavaScript modifies input elements in the browser like adding to a dropdownlist.

    Thursday, January 24, 2019 4:31 PM
  • User-924931093 posted

    Thanks for your replies, I double checked all what you suggested, but the problem still persists, do you have any thoughts on the way I'm validating the XSRF token in the master page? or maybe the logic should be different? or maybe the way I'm changing the Session ID at the login page as i explained in the main post is somehow affecting the ViewState?

    Thursday, January 24, 2019 6:20 PM
  • User-893317190 posted

    Hi basel@Simboliq,

    If you don't set value in Session, it will not automatically set SessionId cookie back to browser.

    And if asp.net doesn't set back sessionId cookie, the property Session.SessionId will always return different value.

    Please check whether you set any value to Session before using Session.SessionId.

    Also, because you are using web-farm, please check the sessionmode of your app and ensure two servers share the same session.

    https://www.c-sharpcorner.com/UploadFile/225740/introduction-of-session-in-Asp-Net/

    Best regards,

    Ackerly Xu  

    Friday, January 25, 2019 4:07 AM
  • User-924931093 posted

    Hello Ackerly, Thanks for your reply and suggestions,

    I did check all the suggested ways to resolve it, here is what i did and my findings:

    1- I checked the machine.config files on both severs (since its running on a web-farm) and there is no tag for MachineKey value to change 

    %windir%\Microsoft.NET\Framework64\[version]\config\machine.config 

    2- I checked both servers ->  IIS configs. [Machine Key] section and I made sure that they do have the same validation and decryption keys and they're not set to AutoGenerate keys

    3- I re-generated a new values for [Machine Key] using PowerShell and updated the values [as described in this link]

    https://support.microsoft.com/en-us/help/2915218/resolving-view-state-message-authentication-code-mac-errors#AppendixA

    4- I checked that the MachineKey values in web.config that matches the values in step 3

    5- I changed the code in master page (in the main question up)

    from this 

    protected void master_Page_PreLoad(object sender, EventArgs e)
            {
                try
                {
                    if (!IsPostBack)
                    {
                        // Set Anti-XSRF token
                        ViewState[AntiXsrfTokenKey] = Page.ViewStateUserKey;
                        ViewState[AntiXsrfUserNameKey] = Session.SessionID.ToString();
                    }
                    else
                    {
                        // Validate the Anti-XSRF token
                        if ((string)ViewState[AntiXsrfTokenKey] != _antiXsrfTokenValue
                            || (string)ViewState[AntiXsrfUserNameKey] != Session.SessionID)
                        {                        
                            Response.Redirect("/Error");
                        }
                    }
                }
                catch (Exception ex)
                {
                    SmtpMailer.SendMsg(ex.Message + ex.Source + ex.StackTrace);
                }
            }

    to this [replaced SessionId  as a value for ViewState[AntiXsrfUserNameKey] with CurrentUser.Code] 

    protected void master_Page_PreLoad(object sender, EventArgs e)
            {
                try
                {
                    if (!IsPostBack)
                    {
                        // Set Anti-XSRF token
                        ViewState[AntiXsrfTokenKey] = Page.ViewStateUserKey;
                        ViewState[AntiXsrfUserNameKey] = CurrentUser.Code;
                    }
                    else
                    {
                        // Validate the Anti-XSRF token
                        if ((string)ViewState[AntiXsrfTokenKey] != _antiXsrfTokenValue
                            || (string)ViewState[AntiXsrfUserNameKey] != CurrentUser.Code)
                        {                        
                            Response.Redirect("/Error");
                        }
                    }
                }
                catch (Exception ex)
                {
                    SmtpMailer.SendMsg(ex.Message + ex.Source + ex.StackTrace);
                }
            }

    The problem still persists!

    This is driving me crazy :( 

    Monday, January 28, 2019 2:53 PM
  • User-893317190 posted

    Hi basel@Simboliq,

    You could refer to the link below for similar solution for csrf token.

    https://stackoverflow.com/questions/1418233/setting-viewstateuserkey-gives-me-a-validation-of-viewstate-mac-failed-error

    If you still have problem, please debug the code in your local machine to see whether it works.

    Best regards,

    Ackerly Xu

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, January 31, 2019 5:36 AM