Cross-Site Request Forgery

Every storefront contains some protected requests that require a high level of security protection. Authenticated shoppers who change their accounts or submit personal data to a server to complete an action typically perform these requests. Users expect that they alone make these requests, and only when they specifically initiate the request.

Cross-site request forgery (CSRF) breaks that expectation by tricking the user’s browser into making this protected request without their knowledge, but with their authorization. Salesforce B2C Commerce has a CSRF protection software library so developers can protect requests against this attack.

The CSRF protection API uses a Synchronizer Token pattern that requires random challenge tokens that are associated with the user's current session. When the user submits content from the page, the server is configured to look for and validate that token. If the token fails to validate, the request is rejected.

For sensitive business functions, including a required security token in HTTP requests can help mitigate CSRF attacks. The reason is that to be successful, the attacker has to know the randomly generated token for a particular session.

The API is exposed via the dw.web.CSRFProtection, which contains the following methods.

  • getTokenName(): Returns the expected parameter name as a string that maps to a CSRF Token.
  • generateToken(): Securely generates a token string for the current user. Tokens are unique per call to generateToken.
  • validateRequest(): Examines a user’s current request to determine if the request contains a valid CSRF token. A token is valid if it was generated for this user’s session in the last 60 minutes.

Here is an example of a form within ISML that uses the CSRF framework to insert the token parameter name and its corresponding value.

<form action="/submit" method="post">
  ...
   <input name="${dw.web.CSRFProtection.getTokenName()}" value="${dw.web.CSRFProtection.generateToken()"> 
</form>

Then, call CSRFProtection.validateRequest() directly in the body of the function or use a middleware implementation to validate the CSRF token.

A best practice for CSRF in SiteGenesis JavaScript controllers is to include CSRFProtection.validateRequest() when handling a specific form action. It's action-specific because not all actions submit data and require CSRF protection.

Here's an example of using the method directly in a SiteGenesis JavaScript controller.

formResult = cartForm.handleAction({
         //Add a coupon if a coupon was entered correctly and is active.
         'addCoupon': function (formgroup) {
            var CSRFProtection = require('dw/web/CSRFProtection');
                if (!CSRFProtection.validateRequest()) { //validate the request
                    app.getModel('Customer').logout();  //log the customer out            
                    app.getView().render('csrf/csrf-failed'); //render an error template
                    return null;
          }
          var status;
          var result = {
          cart: cart,
          EnableCheckout: true,
          dontRedirect: true
          };

SFRA comes with a middleware version of CSRF that performs CSRF checks as a middleware step, with a number of supporting methods, including the following.

  • csrfProtection.validateAjaxRequest to validate the CSRF token on an AJAX request
  • csrfProtection.validateRequest to validate the CSRF token on a non-AJAX request
  • csrfProtection.generateToken to generate a CSRF token to be used in a form and later validated using one of the aforementioned methods

Here's an example of using the middleware.

server.post(
     'Login',
     server.middleware.https,
     csrfProtection.validateAjaxRequest,
     function (req, res, next) {
        var data = res.getViewData();
        if (data && data.csrfError) {
           res.json();
           return next();
        }
 );

CSRF in Business Manager

When creating cartridges for Business Manager, B2C Commerce automatically appends CSRF tokens to every request regardless of the HTTP method. As a result, validate only the CSRF token name and value using CSRFProtection.validateRequest() directly in the body of the function in Business Manager cartridge controllers.

All first-party Business Manager pages and requests are protected by default with CSRF tokens.