MVC4 SPA模板有一个ValidateHttpAntiForgeryTokenAttribute
类,其ValidateRequestHeader
函数解析客户端在组装AJAX调用数据时构造的RequestVerificationToken
标头的两半。客户端AJAX代码从表单上的字段中获取其值,该字段组合了表单令牌和cookie令牌。我觉得将这些组合成一个单一的价值会忽视AntiForgery令牌的目的;出于某种原因,他们是分开的。通过这种方式使用防伪代币,我们是否获得了任何安全保障?
服务器.vbhtml代码(基于Razor):
Public Function GetAntiForgeryToken() As String
Dim cookieToken As String = String.Empty
Dim formToken As String = String.Empty
AntiForgery.GetTokens(Nothing, cookieToken, formToken)
Return cookieToken & ":" & formToken
End Function
...
@If User.Identity.IsAuthenticated Then
@<input id="antiForgeryToken" type="hidden" value="@GetAntiForgeryToken()" />
End If
客户端AJAX代码:
function ajaxRequest(type, url, data, dataType) { // Ajax helper
var options = {
dataType: dataType || "json",
contentType: "application/json",
cache: false,
type: type,
data: data ? ko.toJSON(data) : null
};
var antiForgeryToken = $("#antiForgeryToken").val();
if (antiForgeryToken) {
options.headers = {
'RequestVerificationToken': antiForgeryToken
}
}
return $.ajax(url, options);
}
服务器验证码:
Private Sub ValidateRequestHeader(request As HttpRequestMessage)
Dim cookieToken As String = String.Empty
Dim formToken As String = String.Empty
Dim tokenHeaders As IEnumerable(Of String) = Nothing
If request.Headers.TryGetValues("RequestVerificationToken", tokenHeaders) Then
Dim tokenValue As String = tokenHeaders.FirstOrDefault()
If Not String.IsNullOrEmpty(tokenValue) Then
Dim tokens As String() = tokenValue.Split(":"c)
If tokens.Length = 2 Then
cookieToken = tokens(0).Trim()
formToken = tokens(1).Trim()
End If
End If
End If
AntiForgery.Validate(cookieToken, formToken)
End Sub
什么阻止客户端选择过去使用的任意一对cookieToken和formToken,并在AJAX调用中将它们一起提交以使其通过?这不是防伪功能应该防止的吗?这只是很多愚蠢的开销,不能提高安全性,还是有一部分我缺少?
答案 0 :(得分:1)
什么阻止客户端选择过去使用的任意一对cookieToken和formToken,并在AJAX调用中将它们一起提交以使其通过?这不是防伪功能应该防止的吗?这只是很多愚蠢的开销,不能提高安全性,还是有一部分我缺少?
防伪令牌并非旨在阻止Replay Attack。这是重新使用旧值来创建另一个请求的地方,其目的是欺骗目标机器接受过去的有效指令。
防伪令牌旨在防止Cross Site Request Forgery攻击。
一个简单的例子如下:
bank.com
。evil.com
evil.com
上的网页包含一个隐藏的表单,由JavaScript提交给bank.com/make_money_transfer
当您登录bank.com
并且您的Cookie由浏览器发送时,bank.com
认为您提出请求并在您不知情的情况下启动汇款,因为从服务器的角度来看,一切都很好。
令牌旨在通过在请求有效内容中包含某些内容无法由当前域的域自动提交来阻止此操作。由于Same Origin Policy另一个域无法访问令牌值,因此无法通过隐藏表单或任何其他方式发送合法请求。每个会话中的令牌都是唯一的,因此攻击者无法获得可以发送到服务器的令牌和cookie的有效组合。
查看TokenValidator.cs的源代码(尽管是C#而不是VB.NET),我们可以看到ValidateTokens
方法检查令牌中编码的用户名是否与当前HTTP请求中的用户名匹配:
if (!String.Equals(fieldToken.Username, currentUsername, (useCaseSensitiveUsernameComparison) ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase))
{
throw HttpAntiForgeryException.CreateUsernameMismatchException(fieldToken.Username, currentUsername);
}
这将阻止攻击者抓取旧版本的表单字段值并在其CSRF攻击中提交 - 他们的编码用户名将与其受害者的登录用户不匹配。