-
Notifications
You must be signed in to change notification settings - Fork 804
Security Preventing CSRF attacks (Implementing AntiForgery)
Hi everyone;
Credits: I borrowed heavily from this post.
In my first contribution to the community of this great platform, I will (try to) show how to prevent CSRF attacks. To understand what we're up against, take a look at this informative video from Troy Hunt and this post from Sumit Maitra.
Basically, you'd wanna add the "AntiForgeryToken()" to your submit forms. That would be a very straightforward task if we were sending HTML form data. Because our AJAX request send JSON data, we may follow these steps and we'll be all set:
First, add "@Html.AntiForgeryToken()" to your submit button (AccountLogin.cshtml). This will generate the AntiForgeryToken and the Cookie on the client side:
<button id="~_LoginButton" type="submit" class="btn btn-primary">
@Html.AntiForgeryToken() //<--------------------------------------
@Texts.Forms.Membership.Login.SignInButton
</button>
Modify LoginPanel.ts. This will send the previously generated token to the Login method :
this.byId('LoginButton').click(e => {
e.preventDefault();
if (!this.validateForm()) {
return;
}
var request = this.getSaveEntity();
var token = $('input[name="__RequestVerificationToken"]').val();//<----------
var headers = {};//<--------------------------------------------------------------------------
headers['X-RequestVerificationToken'] = token;//<----------------------------------
Q.serviceCall({
url: Q.resolveUrl('~/Account/Login'),
request: request,
headers: headers, // <--------------------------------
onSuccess: function (response) {
var q = Q.parseQueryString();
var returnUrl = q['returnUrl'] || q['ReturnUrl'];
if (returnUrl) {
window.location.href = returnUrl;
}
else {
window.location.href = Q.resolveUrl('~/');
}
}
});
Define "ValidateJsonAntiForgeryTokenAttribute":
namespace MultiTenancy
{ using System;
using System.Web;
using System.Web.Helpers;
using System.Web.Mvc;
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class,
AllowMultiple = false, Inherited = true)]
public sealed class ValidateJsonAntiForgeryTokenAttribute
: FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
var httpContext = filterContext.HttpContext;
var cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName];
AntiForgery.Validate(cookie != null ? cookie.Value : null,
httpContext.Request.Headers["X-RequestVerificationToken"]);
}
}
}
Finally, add the "ValidateJsonAntiForgeryToken" attribute to the POST login method of the Account controller:
[HttpPost, JsonFilter]
[ValidateJsonAntiForgeryToken] <------------
public Result<ServiceResponse> Login(LoginRequest request)
{
return this.ExecuteMethod(() =>
{
//code
});
}
These same simple steps should be applied to the other submit forms (such as the SignUp and ChangePassword forms).
Copyright © Serenity Platform 2017-present. All rights reserved.
Documentation | Serene Template | Live Demo | Premium Support | Issues | Discussions