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:
- Once the client requests an HTML page with a form, the server generates two random tokens.
- 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.
- Each time a user submits the form, the client sends tokens back to the server.
- If the server receives a request that does not include both tokens or if one of tokens was modified, the server rejects the request.
To use anti-forgery tokens in your application callbacks:
- Make sure that the application references the System.Web.WebPages.dll assembly.
Create a master page that generates an AntiForgery token:
<form id="form1" runat="server"> <%= System.Web.Helpers.AntiForgery.GetHtml() %> </form>During master page initialization, add a handler for the
Page.PreLoadevent:In the event handler, call the Validate method to check whether the token is valid:
Validate Anti‑Forgery Tokens for Individual Controls
The following DevExpress ASP.NET Web Forms components implement custom request processing:
Internal requests from these controls are processed by the DevExpress HTTP module instead of the standard page handler. As a result, the AntiForgery.Validate() call from Page_PreLoad is not executed for these requests. You must apply the additional steps below.
Note
The following steps supplement, but do not replace, the anti‑forgery token validation for callbacks described above. Implement both mechanisms for complete CSRF protection.
Make sure that a master page generates an anti-forgery token:
<form id="form1" runat="server"> <%= System.Web.Helpers.AntiForgery.GetHtml() %> </form>Add a client function that injects the token into the
RequestVerificationTokenHTTP request header.<script> function onBeforeSend(spreadsheet, e) { e.request.setRequestHeader("RequestVerificationToken", document.querySelector('input[name=__RequestVerificationToken]').value); } </script>Pass the function name to the control’s
BeforeSendproperty to add the token to all internal HTTP requests.<dx:ASPxFileManager ID="fileManager" runat="server" ClientSideEvents-BeforeSend="onBeforeSend"> <!-- ... --> </dx:ASPxFileManager>Implement
IHttpModuleSubscriberto validate theRequestVerificationTokenHTTP request header against the anti‑forgery cookie token. Reject all unsafe requests that fail validation.public class AntiforgeryOfficeHttpModuleSubscriber : IHttpModuleSubscriber { bool IsUploadRequest(HttpRequest request) { return request.Path.EndsWith(DevExpress.Web.Internal .HttpUtils.UploadProgressHttpHandlerPagePath, StringComparison.OrdinalIgnoreCase); } bool IsOfficeRequest(HttpRequest request) { return request.Path.EndsWith(DevExpress.Web.Office.Internal. DocumentWorkSessionManagerSubscriber.HandlerName, StringComparison.OrdinalIgnoreCase); } public bool RequestRecipient(HttpRequest request, RequestEvent requestEvent) { return requestEvent == RequestEvent.BeginRequest && (IsOfficeRequest(request) || IsUploadRequest(request)); } public void ProcessRequest() { HttpContext context = HttpContext.Current; HttpRequest request = context.Request; if(!IsUnsafeMethod(request)) return; if(!TryValidateAntiforgery(request, out var error)) { context.Response.StatusCode = 400; context.Response.TrySkipIisCustomErrors = true; context.Response.ContentType = "text/plain"; context.Response.Write("Invalid anti-forgery token."); if(!string.IsNullOrEmpty(error)) context.Response.Write(" " + HttpUtility.HtmlEncode(error)); context.ApplicationInstance.CompleteRequest(); } } bool IsUnsafeMethod(HttpRequest r) { return !(r.HttpMethod == "GET" || r.HttpMethod == "HEAD" || r.HttpMethod == "OPTIONS" || r.HttpMethod == "TRACE"); } bool TryValidateAntiforgery(HttpRequest request, out string error) { error = null; try { string headerToken = request.Headers["RequestVerificationToken"]; string cookieToken = request.Cookies[System.Web.Helpers.AntiForgeryConfig.CookieName] ?.Value; System.Web.Helpers.AntiForgery.Validate(cookieToken, headerToken); return true; } catch(System.Web.Mvc.HttpAntiForgeryException ex) { error = ex.Message; return false; } } }Register the
AntiforgeryOfficeHttpModuleSubscriberat application startup so the DevExpress module can invoke it for matching requests.void Application_Start(object sender, EventArgs e) { ASPxHttpHandlerModule.Subscribe(new AntiforgeryOfficeHttpModuleSubscriber()); }