Skip to main content

Prevent Cross-Site Request Forgery Attacks (CSRF)

  • 3 minutes to read

In Cross-Site Request Forgery (CSRF) attacks, a threat actor tricks an authenticated user into executing unauthorized commands.

Use anti-forgery tokens to protect your application from CSRF attacks. These tokens work as follows:

  1. Once the client requests an HTML page with a form, the server generates two random tokens.
  2. The server adds these tokens in the response. It sends one token as an HttpOnly cookie and places another token in a hidden form field.
  3. Each time a user submits the form, the client sends tokens back to the server.
  4. If the server receives a request that does not include both tokens or if one of tokens was modified, the server rejects the request.

Note

Do not use the GET method to send data modifying requests.

Use Anti-Forgery Tokens

To add anti-forgery tokens to a Razor page:

  1. In the view code, generate an AntiForgery token for a form:

    @using(Html.BeginForm()) {
        @Html.AntiForgeryToken()
        // ...
    }
    
  2. Make certain that AJAX requests for all controls include the token value:

    <script>
    
    if (window.jQuery) {
        $.ajaxPrefilter(function (options, originalOptions, xhr) {
            if (options.dataType && options.dataType !== "html")
                return;
    
            var tokenValue = $('input:hidden[name="__RequestVerificationToken"]').val();
            if (tokenValue && options && options.data && options.data.indexOf('RequestVerificationToken') === -1)
                options.data += "&__RequestVerificationToken=" + tokenValue;
        });
    }
    </script>
    
  3. To validate the request token on the server, apply the ValidateAntiForgeryToken attribute to the corresponding controller action:

    [ValidateAntiForgeryToken]
    public ActionResult EditFormDeletePartial(int id = -1) {
        if(id >= 0)
            EditFormItems.Delete(id);
        return EditFormPartial();
    }
    

Use Anti-Forgery Tokens with Dashboard Designer

To protect against CSRF attacks when using the Dashboard Designer:

  1. Inject an anti-forgery token into the Dashboard’s AJAX request header as follows:

    <script type="text/javascript">
        function onBeforeRender(s, e) {
            var dashboardControl = s.GetDashboardControl();
            dashboardControl.remoteService.headers['__RequestVerificationToken'] = document.querySelector('input[name=__RequestVerificationToken]').value;
        }
    </script>
    
    @using(Html.BeginForm()) {
        @Html.AntiForgeryToken()
    
        @Html.DevExpress().Dashboard(settings => {
            settings.Name = "Dashboard";
            settings.ControllerName = "DashboardWithAntiForgeryToken";
            settings.InitialDashboardId = "editId";
            settings.ClientSideEvents.BeforeRender = "onBeforeRender";
            settings.ClientSideEvents.Init = "onBeforeRender";
        }).GetHtml()
    }
    
  2. Define a custom attribute to validate the anti-forgery token on requests:

    public sealed class DashboardValidateAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter {
        public void OnAuthorization(AuthorizationContext filterContext) {
            if(filterContext == null) {
                throw new ArgumentNullException(nameof(filterContext));
            }
    
            HttpContextBase httpContext = filterContext.HttpContext;
            HttpCookie cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName];
            AntiForgery.Validate(cookie?.Value, httpContext.Request.Headers["__RequestVerificationToken"]);
        }
    }
    
  3. Apply this attribute to the controller action that handles Dashboard callbacks:

    [DashboardValidateAntiForgeryToken]
    public class DashboardWithAntiForgeryTokenController : DevExpress.DashboardWeb.Mvc.DashboardController {
        static readonly DashboardConfigurator dashboardConfigurator;
        static DashboardWithAntiForgeryTokenController() {
            var dashboardInMemoryStorage = new DashboardInMemoryStorage();
            dashboardInMemoryStorage.RegisterDashboard("editId", 
                XDocument.Load(HostingEnvironment.MapPath(@"~/App_Data/PublicDashboard.xml")));
    
            dashboardConfigurator = new DashboardConfigurator();
            dashboardConfigurator.SetDashboardStorage(dashboardInMemoryStorage);
        }
    
        public DashboardWithAntiForgeryTokenController() : base(dashboardConfigurator) {
        }
    }
    
See Also