ASP.net MVC 5提供了帐户控制器和帐户视图。在Register(寄存器)视图中有一行
@Html.AntiForgeryToken()
在寄存器控制器上面有一个属性:
[ValidateAntiForgeryToken]
我决定使用JSON从javascript向服务器发送数据(我使用Angular和$http.post方法)。
我的问题是如何使用javascript发送这个AntiForgeryToken并在控制器中验证它?
还有什么我应该包括的安全措施吗?
AngularJS内置支持XSRF(又名防伪)
XSRF是一种未经授权的网站可以获得用户私人数据。Angular提供了一种对抗XSRF的机制。什么时候执行XHR请求时,$http服务从cookie中读取令牌(默认情况下,XSRF-TOKEN),并将其设置为HTTP标头(X-XSRF-TOKEN)。由于只有在您的域上运行的JavaScript才能读取cookie,您的服务器可以确信XHR来自运行的JavaScript在您的域上。不会为跨域请求设置标头。
如果你想利用这个功能,你必须创建操作过滤器来创建和验证XSRF-TOKEN cookie。这是我使用的简化版本。
AntiForgeryTokenCookieAttribute-使用此属性添加XSRF-TOKEN cookie
/// <summary>
/// Create a XSRF token in the XSRF-TOKEN cookie which is automatically read by AngularJS
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class AntiForgeryTokenCookieAttribute : ActionFilterAttribute
{
private readonly IAntiForgeryVerificationTokenStore _verificationTokenStore = new AntiForgeryVerificationTokenCookieStore(); //TODO: make configurable
private const string CookieName = "XSRF-TOKEN"; //TODO: make configurable
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
var oldVerificationToken = _verificationTokenStore.GetVerificationToken(filterContext.HttpContext.Request);
string newVerificationToken;
string newToken;
AntiForgery.GetTokens(oldVerificationToken, out newVerificationToken, out newToken);
if (newVerificationToken != null)
{
_verificationTokenStore.StoreVerificationToken(filterContext.HttpContext.Response, newVerificationToken);
}
filterContext.HttpContext.Response.Cookies.Add(new HttpCookie(CookieName, newToken));
}
}
ValidateAntiForgeryTokenHeaderAttribute
/// <summary>
/// Validate the XSRF token stored in the X-XSRF-TOKEN header.
/// If the header doesn't exist, look for the XSRF token in the from post.
///
/// Compatible with ValidateAntiForgeryTokenAttribute
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class ValidateAntiForgeryTokenHeaderAttribute : FilterAttribute, IAuthorizationFilter
{
private readonly IAntiForgeryVerificationTokenStore _verificationTokenStore = new AntiForgeryVerificationTokenCookieStore(); //TODO: make configurable
private const string TokenHeaderName = "X-XSRF-TOKEN"; //TODO: make configurable
public void OnAuthorization(AuthorizationContext filterContext)
{
var token = filterContext.HttpContext.Request.Headers[TokenHeaderName];
if (token != null)
{
//validate the token stored in header
var verificationToken = _verificationTokenStore.GetVerificationToken(filterContext.HttpContext.Request);
if (verificationToken == null) { throw new HttpAntiForgeryException("Required verification token not found"); }
AntiForgery.Validate(verificationToken, token);
}
else
{
//validate the token stored in form. Same as ValidateAntiForgeryTokenAttribute
AntiForgery.Validate();
}
}
}
IAntiForgeryVerificationTokenStore
public interface IAntiForgeryVerificationTokenStore
{
string GetVerificationToken(HttpRequestBase request);
void StoreVerificationToken(HttpResponseBase response, string token);
}
AntiForgeryVerificationTokenCookiesStore
public class AntiForgeryVerificationTokenCookieStore : IAntiForgeryVerificationTokenStore
{
public string GetVerificationToken(HttpRequestBase request)
{
if (request == null) { throw new ArgumentNullException("request"); }
var token = request.Cookies[AntiForgeryConfig.CookieName];
return token != null ? token.Value : null;
}
public void StoreVerificationToken(HttpResponseBase response, string token)
{
if (response == null) { throw new ArgumentNullException("response"); }
if (token == null) { throw new ArgumentNullException("token"); }
response.Cookies.Add(new HttpCookie(AntiForgeryConfig.CookieName, token) { HttpOnly = true, Secure = AntiForgeryConfig.RequireSsl });
}
}