Securing Web applications using CSP Nonce

Web Development Sep 8, 2023

In an era where web applications are prevalent, ensuring robust security measures is critical to safeguarding user data and protecting against cyber threats. Content Security Policy (CSP) is a powerful security mechanism that mitigates various attacks, such as Cross-Site Scripting (XSS), data injection, and code injection. When coupled with CSP Nonce, Angular applications can achieve an elevated level of security. In this in-depth blog, we will delve into the concept of CSP, explore the significance of Nonce, and learn how to integrate them effectively into Angular applications.

Understanding Content Security Policy (CSP)

Content Security Policy (CSP) is a security feature supported by modern browsers that allows web developers to define and enforce a set of policies for controlling the sources of content that can be loaded on a web page. These sources include scripts, stylesheets, images, fonts, and more. By specifying the permitted origins for each of these resources, CSP aims to prevent attackers from injecting malicious code into web pages and stealing sensitive user data. This can be achieved by adding CSP in header response.

To enable CSP, a response needs to include an HTTP response header called Content-Security-Policy with a value containing the policy. The policy itself consists of one or more directives, separated by semicolons.

CSP Directives

CSP has its own set of directives that help us implement the policy for the response headers. CSP headers are composed of one or more directives, and if there are multiple directives, they will be separated by semicolons (;). There is a predefined set of source lists that can be used as values for the directives.

Here are a few important directives that we commonly use in Halodoc:-

  1. default-src
  2. script-src
  3. style-src
  4. img-src
  5. connect-src
  6. font-src
  7. object-src

Here's an example of the above-mentioned directives:-

Halodoc way of implementing CSP
Example of the directive(img-src) in which we are white listing the URLs

CSP whitelisting approach

Before implementing a nonce-based CSP, at Halodoc, we used to secure our applications by whitelisting trusted sources through AWS CloudFront and Lambda functions. This process adds these trusted sources to the CSP header and whitelists known domains. However, it's important to note that this approach may have limitations and can be bypassed as per Google's research.  Nonetheless, we can discuss both this approach and the nonce (strict CSP) approach.

Flow of the request using lambda function for CSP
Basic lambda function to add CSP headers

After creating this Lambda function, we can configure it accordingly with AWS CloudFront and S3 requests to protect our application.

Advantages of implementing a whitelisting approach

  1. Specific Resource Control: Whitelisting approach allows you to explicitly specify the trusted sources (domains or URLs) from which content can be loaded and executed on your web page. This specificity reduces the risk of malicious content being inadvertently loaded from untrusted sources.
  2. Protection Against Untrusted Content: This provides protection against various web-based attacks, including Cross-Site Scripting (XSS), data injection, and content spoofing, as only approved sources are allowed. Any attempt to load content from unauthorized sources will be blocked because of whitelisting.
  3. Mitigation of Third-Party Risks: Many web applications use third-party libraries, plugins, or services. Whitelisting enables you to control the origins of such third-party resources, reducing the risk of vulnerabilities or security issues introduced by these external dependencies.
  4. Improved Debugging: When something goes wrong with CSP, it's often easier to debug with a whitelist because you know exactly which domains or URLs are authorized. This can simplify the troubleshooting process and help you quickly identify issues.

While this approach has its benefits, it also comes with a few disadvantages.

  1. Less secure: This can be bypassed in most configurations, which makes it less secure.
  2. Complexity: Creating and maintaining a whitelist can be complex, especially for larger web applications with numerous external dependencies.
  3. Compatibility Issues: Strict policies can break functionality if not configured correctly, leading to potential compatibility problems across different browsers.
  4. False Positives: Overly strict policies may block legitimate resources, affecting the user experience.
  5. Monitoring and Maintenance: Regular monitoring and maintenance are necessary as your application evolves.

To resolve the above-mentioned disadvantages, we have implemented CSP Nonces in our applications.

Why CSP Nonce?

CSP(Content security policy) Nonce is also known as strict CSP, which provides enhanced CSP level 3 security. This type of CSP is recommended to use in web pages which is rendered server side. When a policy is configured with 'strict-dynamic', all script code approved by a nonce is allowed to load additional dependencies. (like third-party lib and lazy loading of bundles)

We can implement this by generating a nonce on the server-side (Node.js) and adding it as part of the CSP header for every page load request (as recommended by Google CSP evaluator for script-src, object-src, and base-uri). We can also add the same generated nonce to the script tag loaded in index.html or the root page.

There are two types of strict CSPs.

  1. nonce
  2. hash

How do these two CSPs work:

nonce:- A nonce is a security feature that helps us allow specific inline scripts and styles to execute on our web page by using a cryptographic nonce (a number used once). This is a dynamically generated random number generated by the server and included in CSP headers, as well as in script and style tags on the web page. Only scripts and style tags with matching nonce attributes will be allowed to execute, providing protection against cyber attacks. However, it's crucial to ensure that our nonce is generated on the server side and is not easily guessable.

Advantages of using CSP nonce

A nonce based implementation have many benefits such as mentioned below

  1. It uses a random number that is very difficult for attackers to guess, so the browser engine won't allow the execution of scripts that don't match the nonce attributes.
  2. It is based on a dynamically generated nonce value, rather than relying on adding whitelist URLs, which can be bypassed
  3. It doesn't need to change each time, if we have any new implementation, its structure will remain the same and won't require customization.
  4. This won't allow inline scripts and events like eval and javascript:.

The image below shows how headers will have that nonce attribute.

CSP with nonce(random value)

hash:- So protect attack from cyber attack in this type we add hash to every inline <script> tag. Each script tag will have different hash.

Nonce vs Hash

Nonce and hash-based Content Security Policy (CSP) are two different approaches to implementing CSP, each with its own advantages and use cases:

Nonce

  • Provides a way to dynamically allow inline scripts with unique nonces.
  • May be preferred when you have fine-grained control over script generation and can generate nonces for each script dynamically.
  • Can be more flexible when dealing with dynamic content generation.

Hash

  • Requires precomputing the hash of scripts before defining the policy.
  • Provides a more static way to allow specific script content.
  • May be preferred when you want to explicitly specify which scripts, including external ones, are allowed by their content.

Browser compatibility

According to the official CSP website, it is recommended to use the latest versions of browsers for CSP since most browsers support CSP, except for a few specific versions of certain browsers. The minimum required Chrome browser version is 52 and above to support the strict-dynamic feature. Similarly, there are specific browsers that require minimum versions to support this feature. However, CSP is backward compatible with specific levels, such as level 1, and level 2 is compatible with level 3.

Minimum supported browser versions
Supported browser versions, categorized by device

We can deploy strict-dynamic in backward compatible way without using user agent sniffing like this

During our implementation of CSP nonce, we discovered that some of our users were still using old browsers that don't support CSP 3 features. For them, we provided some reminders to upgrade their browsers to enhance the application's security. To check for more compatibility details, one can refer to this official website.

Halodoc way of implementing CSP nonce

As we are using SSR for handling responses, we decided to use nonce and followed these steps to apply CSP nonce in Angular-based applications. So before implementing nonce we need to do few analysis like how and what server will be used for generating nonce, approach for generating dynamic and unique nonce.

After doing the above analysis, we followed these steps to implement CSP nonce:-

step-1: - In the server.ts file, add a set of directives that we want to include as trusted sources, like the one below. We need to do this because nonces are required for scripts, but we still have other URLs that need to be added to our allowlist.

list of csp source directives

step-2:- Add  security_header.json file  to create json for the urls which we want to allow and mark as trusted url for our web application for outdated browsers. This will be a raw configuration and later can be used accordingly.
note: - We need to update the file name security_headers.json with incremental versions each time we add a new URL to the allowlist. This is necessary only if we have included caching for a better experience.

step-3:-  By using helmet.js, we can add CSP headers as shown below inside the server.use function in the server.ts file, which will include the sources we want in the allowlist.

step-4:- Generate nonce which will later use for adding in http headers and scripts. Function randomString() uses crypto lib to generate unique random number for each http response.

Adding nonce in each http response

step-5:- Using this code we can target all the scripts and add nonce to mark it as trusted source.

step-6:- We need to remove all inline event, scripts from HTML template whereever it is used, We have to add alternate solution for that otherwise attackers can inject malicious script anyways nonce will take care of that and wont allow such markups.

step-7:- If using eval() functions in application we need to remove it to secure application but if this can not be removed due to some reason then still we can have csp nonce by adding unsafe-eval but this will make application less secure.  

Above mentioned steps are to implement CSP nonce with required source we want to allow to use in our application. By following these steps csp nonce can be implemented and help us to improve application security from XSS attacks.

How to evaluate implemented csp

We can evaluate csp implementation by available online evaluators such as CSP evaluator . Will see the results as we can see in screenshots below.

CSP with nonce implementation 

Conclusion

We have implemented CSP nonce in Halodoc websites by using explained approach in blogs. Implementing a Content Security Policy (CSP) with a nonce provides a robust and effective method for mitigating various types of attacks, such as cross-site scripting (XSS). By dynamically generating and including nonces in the CSP directives, websites can significantly enhance their security posture. This approach ensures that only scripts with the correct nonce values are executed, reducing the risk of unauthorized code execution and enhancing overall user trust. As online threats continue to evolve, adopting CSP with nonces remains a valuable strategy to safeguard web applications and their users' sensitive data.

Join us

Scalability, reliability and maintainability are the three pillars that govern what we build at Halodoc Tech. We are actively looking for engineers at all levels and  if solving hard problems with challenging requirements is your forte, please reach out to us with your resumé at careers.india@halodoc.com.


About Halodoc

Halodoc is the number 1 all around Healthcare application in Indonesia. Our mission is to simplify and bring quality healthcare across Indonesia, from Sabang to Merauke. We connect 20,000+ doctors with patients in need through our Tele-consultation service. We partner with 3500+ pharmacies in 100+ cities to bring medicine to your doorstep. We've also partnered with Indonesia's largest lab provider to provide lab home services, and to top it off we have recently launched a premium appointment service that partners with 500+ hospitals that allow patients to book a doctor appointment inside our application. We are extremely fortunate to be trusted by our investors, such as the Bill & Melinda Gates Foundation, Singtel, UOB Ventures, Allianz, GoJek, Astra, Temasek, and many more. We recently closed our Series D round and in total have raised around USD$100+ million for our mission. Our team works tirelessly to make sure that we create the best healthcare solution personalised for all of our patient's needs, and are continuously on a path to simplify healthcare for Indonesia.

Amit Kumar Urmaliya

WEB SDE II - Passionate about crafting seamless web experiences. Expertise in front-end technologies, turning challenges into elegant solutions.