0

I am working on an Asp.net webforms application. I am trying to implement anti forgery token functionality in the application.

I have a test case where the application is called from a script in a different file (CSRF issue) using XHR. The solution I have implemented works properly until I change a value of ViewState in the script.

Following is the whole scenario.

Look at "\r\n" blah blah blah... ; in below script.

External script (CSRF attack script):

    var xhr = new XMLHttpRequest();
    xhr.open("POST", "MyAppDomain", true);
    xhr.setRequestHeader("Accept", "text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8");
    xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
    xhr.setRequestHeader("Content-Type", "multipart\/form-data; boundary=---------------------------12421522427704");
    xhr.withCredentials = true;
    var body = "-----------------------------12421522427704\r\n" +
      "Content-Disposition: form-data; name=\"Element\"\r\n" +
      "\r\n" +
      "Search here...\r\n" +
      "-----------------------------12421522427704\r\n" +
      "Content-Disposition: form-data; name=\"ddlRecordPerPage_Value\"\r\n" +
      "\r\n" +
      "-----------------------------12421522427704\r\n" +
      "Content-Disposition: form-data; name=\"__EVENTARGUMENT\"\r\n" +
      "\r\n" +
      "btnEditProfileSave|event|Click\r\n" +
      "-----------------------------12421522427704\r\n" +
      "Content-Disposition: form-data; name=\"__VIEWSTATE\"\r\n" +
      "\r\n" +
      "\r\n" blah blah blah... ;
    var aBody = new Uint8Array(body.length);
    for (var i = 0; i < aBody.length; i++)
        aBody[i] = body.charCodeAt(i);
    xhr.send(new Blob([aBody]));

My solution in the application:

If Not Page.IsPostBack Then
    ViewState("AntiforgeryToken") = ""
Else
    Dim OutString As String = If(Not String.IsNullOrEmpty(Convert.ToString(ViewState("AntiforgeryToken"))), Convert.ToString(ViewState("AntiforgeryToken")), "")
    If String.IsNullOrEmpty(OutString) AndAlso OutString = "initialize" Then
        Throw New Exception("Unknown request source.")
        Ext.Net.X.Redirect(AppPath() & "/Login.aspx", "Invalid request scope.")
    End If
    AntiforgeryChecker.Check(Me.Page, OutString)
    ViewState("AntiforgeryToken") = OutString
End If

Code block explanation:

When one of my page loads, I am setting encrypted GUID in the ViewState as well as in the session. After it, when a user makes any server call, it will only compare the value of ViewState and session. If the decrypted value of the ViewState does not match with the decrypted value of session, indicates that the method is being called from the outside of the application.

Above solution works perfectly.

But when I change the value of ViewState as following:

"**Test**\r\n" blah blah blah... ;

My code fails to validate it because it goes to the If Not Page.IsPostBack Then part and sets blank ViewState value. It occurs just by adding "Test" in the script. Anyone with Asp.net experience may know the issue here. Please explain the exact issue and the solution this case...

Regards

Maharshi
  • 1,178
  • 1
  • 14
  • 37

1 Answers1

0

So I have found the solution.

  1. What I could do here is I can check which control caused the postback.

  2. Now here when I reload the page it will return me nothing but when injected script causes the postback it returns me the control which caused the postback (here in my case it returns ScriptManager).

  3. Based on the control I can differentiate actual post back event and do further code accordingly.

Please let me know if this solution is valid or it can cause an issue in future. Found solution from this post.

Solution:

Protected Overrides Sub OnLoad(ByVal e As EventArgs)
    Try
        Dim ControlPostBack As Control = GetControlThatCausedPostBack(Me)
        If Not Page.IsPostBack Then
            If ControlPostBack Is Nothing Then
                ViewState("AntiforgeryToken") = ""
            End If
        End If

        Dim OutString As String = Convert.ToString(ViewState("AntiforgeryToken"))
        AntiforgeryChecker.Check(Me.Page, OutString, ControlPostBack)
        ViewState("AntiforgeryToken") = OutString

    Catch ex As Exception
        Handled()
    End Try
End Sub


Private Function GetControlThatCausedPostBack(page As Page) As Control
    Dim ctrl As Control = Nothing
    Dim ctrlName As String = page.Request.Params.[Get]("__EVENTTARGET")
    If Not [String].IsNullOrEmpty(ctrlName) Then
        ctrl = page.FindControl(ctrlName)
    End If
    Return ctrl
End Function
Maharshi
  • 1,178
  • 1
  • 14
  • 37