Fortifying Sitecore Web Applications: 7 Best Security Practices & Solutions

In the ever-evolving landscape of web development, ensuring the security of your web applications is paramount. This holds especially true for platforms like Sitecore, a powerful content management system used by many organizations worldwide. To protect your Sitecore web applications from potential threats and vulnerabilities, it’s essential to implement robust security standards. In this blog, we will delve into the key aspects of security standards for Sitecore web applications and explore the best practices to fortify your digital assets.

Security Standards – Sitecore Web Application

Security plays an indispensable role in safeguarding any .NET application, ensuring the perpetual safety and integrity of your servers and applications. Regular employment of security tools and site scans is essential to ascertain that best practices are consistently upheld, preserving the sanctity of your website and environments.

In this blog, we’ll explore the critical realm of security standards for Sitecore web applications. Drawing from recent experiences in configuring security standards for Sitecore websites hosted on both IIS and Azure PaaS, we’ll delve into the essential security practices that demand unyielding attention. Before your application goes live, it’s imperative to verify that all necessary security measures are firmly in place.

We’ll also look at the various security errors encountered and the corresponding adjustments made in the Web.config and IIS configurations to fortify your Sitecore web applications comprehensively.

1. Content-Security-Policy

The first and foremost is the content-security-policy – It is always crucial to apply the right Content-Security-Policy on the website. There might be various third-party websites in your application to load assets so you need to allow only those specific sites and restrict others. So it is very important to have the right content-security-policy in place. The below is one example of content-security-policy we’ve applied on one of the website.


<add name="Content-Security-Policy" value="default-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src * data: blob:; script-src 'self' 'unsafe-inline' 'unsafe-eval' *; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com juicer.io *.juicer.io *.azureedge.net; font-src 'self' 'unsafe-inline' https://fonts.gstatic.com *.azureedge.net *.juicer.io data:; upgrade-insecure-requests; connect-src *; frame-src *; object-src 'none'" />

It’s crucial to configure the content-security-policy (CSP) before publicly launching the website and exposing your server’s data beyond the network perimeter. However, the specifics of implementing the policy and the exact behavior may vary based on the content security needs of the website/application.

For instance, a CSP typically uses directives such as default-src, img-src, style-src, script-src, font-src, connect-src, and object-src to define the allowed sources for different types of content (e.g., images, scripts, stylesheets). If a directive is missing for a specific content type, the browser often falls back to the default-src directive, inheriting its settings for that content type.

It’s crucial to accurately define these directives based on the specific needs and sources required for the website/application to prevent potential security risks such as cross-site scripting (XSS), data injection, and other attacks. Therefore, the details and accuracy of the CSP implementation should align with the security requirements of the web platform in question.

2. X-Content-Type-Options

<add name="X-Content-Type-Options" value="nosniff" />

The value of X-Content-Type-Options in security headers should be “nosniff.” This setting prevents web browsers from attempting to MIME-sniff or interpret the content type of a response, reducing the risk of certain types of attacks, such as MIME confusion attacks, where browsers may incorrectly interpret content types and execute potentially harmful scripts. By setting X-Content-Type-Options to “nosniff,” it instructs the browser to honor the declared content type and not try to infer it from the content itself, enhancing security.

3. X-Xss-Protection

<add name="X-Xss-Protection" value="1; mode=block" />

The recommended value for X-XSS-Protection in security headers is “X-XSS-Protection: 1; mode=block”. This setting enables the Cross-Site Scripting (XSS) filter built into most modern web browsers. When set to “1; mode=block”, it tells the browser to detect and prevent certain types of reflected XSS attacks.

The “mode=block” directive instructs the browser to prevent rendering the page if an XSS attack is detected, effectively blocking the attack. It acts as an additional layer of security to mitigate the impact of XSS vulnerabilities that might exist in the web application. This header helps protect users by automatically detecting and stopping malicious scripts from executing in the browser.

4. Strict-Transport-Security

<add name="Strict-Transport-Security" value="max-age=31536000; includeSubdomains; preload" />

The recommended value for Strict-Transport-Security in security headers is “Strict-Transport-Security: max-age=<time>; includeSubDomains; preload”.

  • “max-age=<time>” indicates the duration, in seconds, for which the browser should enforce HTTPS for the domain. For example, “max-age=31536000” (1 year) tells the browser to enforce HTTPS for the domain for one year.
  • “includeSubDomains” ensures that the HSTS policy applies not only to the main domain but also to all subdomains.
  • “preload” submits the domain to the HSTS preload list, allowing browsers to automatically enforce HSTS for the domain even before the initial visit, thereby preventing insecure HTTP connections.

This header is crucial for ensuring that the entire website, including subdomains, is accessed only via HTTPS. It helps protect users from man-in-the-middle attacks and other security threats by forcing the use of secure, encrypted connections and preventing downgrade attacks that attempt to switch from HTTPS to HTTP.

5. X-Frame-Options:

<add name="X-Frame-Options" value="SAMEORIGIN" />

The value of the X-Frame-Options security header should ideally be set to either “DENY”, “SAMEORIGIN”, or “ALLOW-FROM uri”.

  • DENY: This option ensures that the web page cannot be displayed in a frame or iframe on any site. It offers the highest level of protection against clickjacking attacks but might restrict legitimate uses of framing the content.
  • SAMEORIGIN: This option allows the page to be framed only by pages from the same origin as the website. It permits framing if the site embedding the content has the same domain as the site serving the content. This option balances security and functionality.
  • ALLOW-FROM uri: This option allows the page to be framed only by the specified URI. It permits framing if the site embedding the content is from the provided URI. However, this directive is being deprecated in modern browsers due to security concerns.

Setting X-Frame-Options to one of these values helps in preventing clickjacking attacks by controlling how the web page can be embedded in other sites. Choosing the appropriate value depends on the specific requirements of the website, balancing security needs with functional considerations.

Here is the entire script that can be inserted into the <customHeaders> section within the web.config file. You’ll need to adjust the content-security-policy header according to your requirements.

Please note that in the Sitecore default instance 10.2’s web.config file, you’ll find below headers already configured. However, despite their presence in the file, they may not be reflected in the application.

<location path="sitecore">
    <system.webServer>
      <httpProtocol>
        <customHeaders>
          <remove name="X-Content-Type-Options" />
          <remove name="X-XSS-Protection" />
          <remove name="Content-Security-Policy" />
          <add name="X-XSS-Protection" value="1; mode=block" />
          <add name="X-Content-Type-Options" value="nosniff " />
          <add name="Content-Security-Policy" value="default-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' data:; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' 'unsafe-inline' https://fonts.gstatic.com; upgrade-insecure-requests; block-all-mixed-content;" />
        </customHeaders>
      </httpProtocol>
    </system.webServer>
  </location>

You have two options either explicitly add these configurations on the IIS which will update the web.config file or add again in the web.config file at a correct place.

Within <system.webServer>ADDHERE</system.webServer> in the web.config you can add the something like below. Note: Do update the configuration as per your web application.

<httpProtocol>
      <customHeaders>
			<remove name="X-Powered-By" />
			<add name="Content-Security-Policy" value="default-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src * data: blob:; script-src 'self' 'unsafe-inline' 'unsafe-eval' *; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com juicer.io *.juicer.io *.azureedge.net; font-src 'self' 'unsafe-inline' https://fonts.gstatic.com *.azureedge.net *.juicer.io data:; upgrade-insecure-requests; connect-src *; frame-src *; object-src 'none'" />
			<add name="X-Content-Type-Options" value="nosniff" />
			<add name="X-Xss-Protection" value="1; mode=block" />
			<add name="Strict-Transport-Security" value="max-age=31536000; includeSubdomains; preload" />
			<add name="X-Frame-Options" value="SAMEORIGIN" />
      </customHeaders>
    </httpProtocol>

6. Custom Error Page

Every project uses different application to test the security of the application. We receive different set of security issues based on the parameters set by the application. One of the security error we received was “Poor Error Handling: Unhandled Exception”

Explanation
A runtime error message was found. A runtime error message indicates that an unhandled exception was generated in your web application code. Unhandled exceptions are circumstances in which the application has received user input that it did not expect and doesn’t know how to deal with. In many cases, an attacker can leverage the conditions that cause these errors in order to gain unauthorized access to the system. Recommendations include adopting a uniform error handling scheme and never revealing information that could be used by an attacker in an error message.


Summary: A runtime error message was found. A runtime error message indicates that an unhandled exception was generated in your web application code. Unhandled exceptions are circumstances in which the application has received user input that it did not expect and doesn’t know how to deal with. In many cases, an attacker can leverage the conditions that cause these errors in order to gain unauthorized access to the system. Recommendations include adopting a uniform error handling scheme and never revealing information that could be used by an attacker in an error message.


Implication: The error message may contain the location of the file in which the offending function is located. This may disclose the webroot’s absolute path as well as give the attacker the location of application include files or configuration information. It may even disclose the portion of code that failed.

Solution:

By default you might see something similar to below in the web.config file.

<!--  CUSTOM ERROR MESSAGES
          Set customError mode values to control the display of user-friendly
          error messages to users instead of error details (including a stack trace):

          "On" Always display custom (friendly) messages
          "Off" Always display detailed ASP.NET error information.
          "RemoteOnly" Display custom (friendly) messages only to users not running
          on the local Web server. This setting is recommended for security purposes, so
          that you do not display application detail information to remote clients.
    -->
    <customErrors mode="Off" />
  1. Create the maintenance page: Design an HTML/Aspx page (e.g., maintenance.html) that will serve as the maintenance notification page.
  2. Configure web.config: Use the <customErrors> section in your web.config file to redirect remote requests to the maintenance page.
<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite">
      <error statusCode="500" redirect="~/Errors/500.aspx" />
      <!-- Add more error codes and respective pages as needed -->
</customErrors>

Explanation:

  • mode="RemoteOnly": Specifies that custom errors are shown to remote users, while local users will see detailed errors.
  • redirectMode="ResponseRewrite": Redirects to a specified error page while maintaining the original request URL in the browser.

It is standard practice for configuring custom error pages in ASP.NET applications using the web.config file. This setup allows for better error handling by displaying custom error pages to remote users while showing detailed errors only to local users for debugging purposes.

It’s considered a best practice because it helps improve the user experience by presenting friendly error messages to site visitors while preventing sensitive information about the application’s configuration or structure from being exposed to potential attackers. Additionally, it assists developers in diagnosing issues by displaying detailed error information during local development and testing.

7. HTTP Cookies only

<system.web>
    <httpCookies httpOnlyCookies="true" requireSSL="true" />
</system.web>

The HTTPOnly attribute is like a protective shield for cookies used in web applications. It’s a security feature that stops sneaky scripts from peeking at your cookies. When this attribute is set, it keeps cookies safe from being accessed by any scripts running in your browser, like JavaScript.

Here’s why HTTPOnly is really important:

  1. Keeping Hackers Away: It guards against a type of attack called Cross-Site Scripting (XSS). This attack tries to sneak malicious scripts into web pages to steal your cookies. With HTTPOnly, even if a sneaky script gets in, it can’t lay its hands on your cookies.
  2. Securing Your Secrets: Cookies often carry important stuff, like session IDs or special codes for logging in. HTTPOnly makes sure that this info stays safe and doesn’t get swiped by someone poking around where they shouldn’t.
  3. Following Security Rules: Big names in web security, like OWASP, say that using HTTPOnly is a smart move. It’s a good practice that helps protect your website from common security risks.

By setting cookies with the HTTPOnly flag, developers can build stronger defenses against certain kinds of cyber attacks. It’s like locking the door to your cookie jar and keeping those treats safe from the wrong hands!

Conclusion:

While these security best practices provide a solid foundation for Sitecore web application security, they represent just a part of a comprehensive strategy. After receiving a report from the client highlighting vulnerability issues on the UAT application, I had the opportunity to address these issues. The report contained several errors, and I’ve highlighted a few critical ones that require immediate attention on the UAT/Production servers. Constant vigilance, regular assessments, user training, and staying updated on patches and third-party components are equally vital. A robust incident response plan and proactive monitoring are essential for a holistic security approach in the ever-evolving cybersecurity landscape.

Feel free to share your thoughts and additional security measures you’ve implemented in your web application development. Your insights contribute to a broader understanding and implementation of effective security practices across the digital landscape.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.