我正在开发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经验的人都可以在这里知道这个问题。请解释这个案例的确切问题和解决方案......
此致
答案 0 :(得分:0)
所以我找到了解决方案。
我在这里可以做的是我可以检查哪个控件导致了回发。
现在,当我重新加载页面时,它将返回给我什么,但是当注入脚本导致回发时它返回导致回发的控件(在我的情况下它返回ScriptManager)。
根据控件,我可以区分实际的回发事件,并相应地做进一步的代码。
如果此解决方案有效或将来可能导致问题,请与我们联系。 找到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