这是我发现的。我最终使用了 geedubb 所描述的 LosFormatter,方法是将以下代码添加到 MasterPage,并将值分配给一个隐藏的输入,该输入与 ajax 请求一起发回。当我发布 HttpCookie.HttpOnly 属性仍然在 ajax 请求上回发 cookie 的问题时,我没有意识到,因此可以将其设置为 false。
internal string GetToken()
{
// call the static method to guarantee LosFormatter remains threadsafe
return GetToken(_antiXsrfTokenValue);
}
private static string GetCurrentUserName()
{
var currentUser = HttpContext.Current.User.Identity;
return (currentUser == null) ? string.Empty : currentUser.Name;
}
private static string GetToken(string token)
{
var los = new System.Web.UI.LosFormatter(true, token);
var writer = new System.IO.StringWriter();
var data = new Dictionary<string,string>();
data.Add("TokenValue",token);
data.Add("UserNameKey", GetCurrentUserName());
los.Serialize(writer, data);
return writer.ToString();
}
internal static void Validate(string token)
{
var request = HttpContext.Current.Request;
var requestCookie = request.Cookies[AntiXsrfTokenKey];
var antiXsrfTokenValue = requestCookie.Value;
var los = new System.Web.UI.LosFormatter(true, antiXsrfTokenValue);
var xsrfData = (Dictionary<string,string>)los.Deserialize(token);
if (xsrfData["TokenValue"] != antiXsrfTokenValue || xsrfData["UserNameKey"] != GetCurrentUserName())
{
throw new System.Security.Authentication.AuthenticationException("Validation of Anti-XSRF token failed.");
}
}
最初,我尝试使用相同的代码发送 _VIEWSTATE 隐藏输入的值
var los = new System.Web.UI.LosFormatter(true, antiXsrfTokenValue);
var ajaxViewState = los.Deserialize(token)
但这引发了一个错误,指出提供的密钥无法反序列化字符串。显然设置
Page.ViewStateUserKey = _antiXsrfTokenValue;
具有比单独提供的密钥更复杂的密钥。如果有人知道如何使用 userKey 反序列化视图状态字符串,我会很感兴趣。
我提供的方法的唯一问题是回发的字符串的大小 - GUID + 6 个字符的用户名长度为 1976 个字符!!!!
如果再次处理这个问题,我会引用 System.Web.WebPages.dll(在 mvc 项目中使用),并使用在 MVC 中创建 Html.AntiForgeryToken 的相同方法
namespace System.Web.Helpers
{
/// <summary>
/// Provides access to the anti-forgery system, which provides protection against
/// Cross-site Request Forgery (XSRF, also called CSRF) attacks.
/// </summary>
public static class AntiForgery
{
public static void GetTokens(string oldCookieToken, out string newCookieToken, out string formToken)
public static void Validate()