在Asp.net webform应用程序中验证Anti Forgery Token失败

时间:2017-07-25 11:45:24

标签: c# asp.net vb.net webforms antiforgerytoken

我正在开发Asp.net webforms应用程序。我正在尝试在应用程序中实现防伪令牌功能。

我有一个测试用例,其中使用XHR从不同文件(CSRF问题)中的脚本调用应用程序。我实现的解决方案正常工作,直到我在脚本中更改ViewState的值。

以下是整个方案。

在下面的剧本中查看“\ r \ n”blah blah blah ...;

外部脚本(CSRF攻击脚本):

    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]));

我在应用程序中的解决方案:

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

代码块说明:

当我的一个页面加载时,我在ViewState以及会话中设置了加密的GUID。之后,当用户进行任何服务器调用时,它只会比较ViewState和会话的值。如果ViewState的解密值与会话的解密值不匹配,则表示正在从应用程序外部调用该方法。

以上解决方案完美无缺。

但是当我按照以下方式更改ViewState的值时:

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

我的代码无法验证它,因为它转到If Not Page.IsPostBack Then部分并设置空白ViewState值。它只是通过在脚本中添加“Test”来实现。任何有Asp.net经验的人都可以在这里知道这个问题。请解释这个案例的确切问题和解决方案......

此致

1 个答案:

答案 0 :(得分:0)

所以我找到了解决方案。

  1. 我在这里可以做的是我可以检查哪个控件导致了回发。

  2. 现在,当我重新加载页面时,它将返回给我什么,但是当注入脚本导致回发时它返回导致回发的控件(在我的情况下它返回ScriptManager)。

  3. 根据控件,我可以区分实际的回发事件,并相应地做进一步的代码。

  4. 如果此解决方案有效或将来可能导致问题,请与我们联系。 找到this帖子的解决方案。

    <强>解决方案:

    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