Enhancing Security in Sitecore Headless Next.js Apps on XM Cloud

Implementing Content Security Policy (CSP) made simple

March 4, 2024

By Sohrab Saboori

In this blog, we're diving into how to beef up security for your Sitecore Headless Next.js app on XM Cloud using Content Security Policy (CSP). It's a nifty tool that helps keep the bad guys out, especially from sneaky attacks like Cross-Site Scripting (XSS). Whether you're a seasoned pro or just dipping your toes into Sitecore and Next.js, I'll walk you through making your app safer and more robust. Let's get started!

Content Security Policy (CSP) is a crucial security standard that serves as the first line of defence in safeguarding web applications against common security threats such as Cross-Site Scripting (XSS) and data injection attacks. By specifying a set of directives that dictate which resources can be loaded and executed by the browser, CSP enables developers to control the security landscape of their applications with precision.

At its core, CSP works by defining a whitelist of trusted sources for various types of content, such as scripts, stylesheets, images, and more. When a page is loaded, the browser checks the resources against the CSP directives. If a resource violates the policy, the browser blocks it, preventing potential security breaches.

Here are some of the key directives used in CSP:

  • default-src: Defines the default policy for fetching resources such as scripts, styles, images, etc. The default-src directive is applied if a specific resource type's directive is not specified.
  • script-src: Specifies the sources from which scripts can be loaded. This is crucial for preventing XSS attacks by restricting script sources to only trusted domains.
  • style-src: This directive defines the sources from which stylesheets can be loaded. Similar to script-src, it helps mitigate the risk of malicious CSS being injected into the application.
  • img-src: Determines the sources from which images can be loaded. This directive helps in preventing the loading of malicious images from untrusted sources.
  • connect-src: Specifies the URLs the application can connect to using mechanisms like XMLHttpRequest, fetch, WebSocket, etc. This is important for controlling which APIs or endpoints the application can interact with.
  • frame-src: Defines the sources from which frames can be loaded. This directive is essential for preventing clickjacking attacks by ensuring that only trusted iframes are embedded in the application.
  • report-url / report-to: Specifies a URL where the browser can send reports if any resources violate the CSP directives. This is useful for monitoring and analyzing potential security threats.

For more detailed information on CSP, refer to the Content Security Policy documentation provided by Mozilla Developer Network (MDN).

Implementing CSP in Next.js for Sitecore Headless Applications

Configuring CSP in a Next.js application involves setting up HTTP headers that define your security policy. In a Next.js project, this can be done by modifying the next.config.js file to include the CSP headers in the response. Here's an example of how you might set up a basic CSP in next.config.js:

//next.config.js
<span class="hljs-keyword">const</span> securityHeaders = [
  {

   <span class="hljs-attr">key</span>: <span class="hljs-string">'Content-Security-Policy'</span>,
            <span class="hljs-attr">value</span>:
              <span class="hljs-string">`default-src  </span><span class="hljs-string">'self'</span><span class="hljs-string">  </span><span class="hljs-string">'unsafe-eval'</span><span class="hljs-string"> `</span> +
              <span class="hljs-string">`script-src </span><span class="hljs-string">'self'</span><span class="hljs-string"> </span><span class="hljs-string">'unsafe-inline'</span><span class="hljs-string"> https:</span><span class="hljs-comment"><span class="hljs-string">//www.google-analytics.com  `</span> +</span>
              <span class="hljs-string">`style-src  </span><span class="hljs-string">'self'</span><span class="hljs-string"> </span><span class="hljs-string">'unsafe-inline'</span><span class="hljs-string">  https:</span><span class="hljs-comment"><span class="hljs-string">//fonts.googleapis.com; `</span> +</span>
              <span class="hljs-string">`img-src  </span><span class="hljs-string">'self'</span><span class="hljs-string"> data:  https:</span><span class="hljs-comment"><span class="hljs-string">//analytics.twitter.com  `</span> +</span>
              <span class="hljs-string">`font-src  </span><span class="hljs-string">'self'</span><span class="hljs-string"> data: https:</span><span class="hljs-comment"><span class="hljs-string">//fonts.gstatic.com; `</span> +</span>
              <span class="hljs-string">`connect-src  </span><span class="hljs-string">'self'</span><span class="hljs-string"> <span class="hljs-subst">${jssConfig.sitecoreApiHost}</span> *.googlesyndication.com ; `</span> +
              <span class="hljs-string">`frame-src </span><span class="hljs-string">'self'</span><span class="hljs-string"> </span><span class="hljs-string">'unsafe-inline'</span><span class="hljs-string"> <span class="hljs-subst">${jssConfig.sitecoreApiHost}</span>;`</span> +
              <span class="hljs-string">`object-src </span><span class="hljs-string">'none'</span><span class="hljs-string">`</span>,
          },
  },

];

<span class="hljs-keyword"><span class="hljs-built_in">module</span></span>.exports = {
  <span class="hljs-keyword">async</span> headers() {
    <span class="hljs-keyword">return</span> [
      {
        <span class="hljs-attr">source</span>: <span class="hljs-string">'/:path*'</span>,
        <span class="hljs-attr">headers</span>: securityHeaders,
      },
    ];
  },
};
</code></pre>

In this example, we've set up directives to control the sources for scripts, styles, images, and connections. The connect-src directive is particularly important in the context of a Sitecore Headless application, as it needs to allow connections to your Sitecore API endpoint.

Considering Sitecore Headless/XM Cloud and Related Services:

  1. XM Cloud and Sitecore Headless API Endpoints: For a Sitecore Headless application on XM Cloud, it's important to include both the XM Cloud API endpoint and the Sitecore Headless SXA endpoint in your connect-src directive. You can use the jssConfig.sitecoreApiHost variable to dynamically include the Sitecore Headless SXA endpoint. For example:
    ```jsx
        connect-src 'self' https://my-xm-cloud-api-endpoint.com ${jssConfig.sitecoreApiHost};
        ```
    
    In <span class="hljs-keyword">this</span> example, **<span class="hljs-string">`https:</span><span class="hljs-comment"><span class="hljs-string">//my-xm-cloud-api-endpoint.com`</span>** is the URL <span class="hljs-keyword">for</span> your XM Cloud API endpoint, and **<span class="hljs-string">`<span class="hljs-subst">${jssConfig.sitecoreApiHost}</span>`</span>** dynamically refers to your Sitecore Headless SXA endpoint. Including both endpoints <span class="hljs-keyword">in</span> the **<span class="hljs-string">`connect-src`</span>** directive ensures secure communication <span class="hljs-keyword">with</span> the necessary Sitecore services.</span>
    </code></pre>
    </li>
    <li><strong>Third-Party Integrations</strong>: If your application integrates with third-party services (e.g.,
    analytics, CDNs, external APIs), make sure to add their URLs to the appropriate CSP directives
    (<strong><code>script-src</code></strong>, <strong><code>img-src</code></strong>, etc.).</li>
    <li><strong>Dynamic Content</strong>: Sitecore Headless applications often render dynamic content, which may include
    inline scripts or styles. You should use <strong><code>'unsafe-inline'</code></strong> or
    <strong><code>'unsafe-eval'</code></strong> in your <strong><code>script-src</code></strong> or
    <strong><code>style-src</code></strong> directives but use these sparingly as they can weaken your CSP.
    </li>
    

Configuring CSP for Development and Production Environments

When implementing Content Security Policy (CSP) in your Sitecore Headless Next.js application, it's crucial to have a flexible setup that allows you to test and debug your policy in development without disrupting the user experience. This is where the Content-Security-Policy-Report-Only header comes in handy. By using this header in development, you can monitor potential CSP violations without actually blocking any content.

Here's how you can configure your CSP to use Content-Security-Policy-Report-Only in development and switch to Content-Security-Policy for production:

  • Determine the Environment

      const isDev = process.env.NODE_ENV === 'development';
        
  • Set the CSP Header Key: Based on the environment, choose the appropriate header key: Content-Security-Policy-Report-Only for development and Content-Security-Policy for production.

      const cspHeaderKey = isDev ? 'Content-Security-Policy-Report-Only' : 'Content-Security-Policy';
        
  • Configure the CSP Header in next.config.js: Use the determined header key and value to set up the CSP header in your Next.js configuration.

      const securityHeaders = [
            {
              key: cspHeaderKey,
              value: cspHeaderValue,
            },
          ];
    
      <span class="hljs-built_in">module</span>.exports = {
        <span class="hljs-function"><span class="hljs-keyword">async</span> <span class="hljs-title">headers</span>(<span class="hljs-params"></span>) </span>{
          <span class="hljs-keyword">return</span> [
            {
              <span class="hljs-attr">source</span>: <span class="hljs-string">'/:path*'</span>,
              <span class="hljs-attr">headers</span>: securityHeaders,
            },
          ];
        },
      };
    </code></pre>
    <p> With this setup, you can test and refine your CSP in development without any disruptions. When you're set to
    launch, the CSP will be enforced in production, enhancing the security of your Sitecore Headless Next.js
    app.</p>
    </li>
    

Testing Your Content Security Policy (CSP)

Once you've configured your CSP, it's important to test it to ensure that it's working as expected and not blocking legitimate resources. A great tool for this purpose is the CSP Evaluator, developed by Google. This online tool allows you to evaluate the effectiveness and security of your CSP policy.

Screenshot of Content Security Policy with sample policy, evaluated results, and security recommendations.

Additionally, for a more integrated testing experience, you can use the CSP Evaluator Chrome Plugin. This plugin allows you to evaluate the CSP of any website you visit directly in your browser, providing real-time feedback and suggestions for improvement.

Screenshot of CSP Evaluator results showing default, script, and style-src directives with evaluations.

By using these tools, you can identify any potential issues with your CSP and make the necessary adjustments to ensure that your Sitecore Headless Next.js app is secure and functions correctly.

Securing Your Next.js App With a Strong CSP

Implementing a robust Content Security Policy (CSP) is a crucial step in securing your Sitecore Headless Next.js application, especially when deployed on XM Cloud. By configuring CSP directives carefully and testing them thoroughly, you can protect your app from common security threats like Cross-Site Scripting (XSS) and data injection attacks. Tools like the CSP Evaluator and its Chrome plugin can be invaluable in ensuring your CSP is effective and doesn't hinder your app's functionality. As you continue to develop and refine your application, keep security at the forefront of your mind, and your CSP will serve as a strong defense in the ever-evolving landscape of web security.

 

Securing Your Next.js App with a Strong CSP
Securing Your Next.js App with a Strong CSP


Photo of Fishtank employee Sohrab Saboori

Sohrab Saboori

Senior Full-Stack Developer

Sohrab is a Senior Front-End Developer with extensive experience in React, Next.js, JavaScript, and TypeScript. Sohrab is committed to delivering outstanding digital solutions that not only meet but exceed clients' expectations. His expertise in building scalable and efficient web applications, responsive websites, and e-commerce platforms is unparalleled. Sohrab has a keen eye for detail and a passion for creating seamless user experiences. He is a problem-solver at heart and enjoys working with clients to find innovative solutions to their digital needs. When he's not coding, you can find him lifting weights at the gym, pounding the pavement on the run, exploring the great outdoors, or trying new restaurants and cuisines. Sohrab believes in a healthy and balanced lifestyle and finds that these activities help fuel his creativity and problem-solving skills.

Second CTA Ogilvy's Legacy

Today, David Ogilvy's influence can still be felt in the world of advertising.

Ogilvy's Influence Example
Emphasis on research Market research is a crucial part of any successful advertising campaign
Focus on headlines A strong headline can make the difference between an ad that is noticed and one that is ignored
Use of visuals Compelling images and graphics are essential for capturing audience attention