# How to apply Content-Security-Policy (CSP) headers using Azure Front Door

[Content-Security-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) (CSP) is a security standard that helps prevent cross-site scripting (XSS) and other code injection attacks by allowing website owners to specify which content sources can be trusted and loaded by their web pages. The CSP policy is defined in an HTTP header sent from the server to the client's web browser, and it can include directives that restrict the types of content allowed, such as images, scripts, stylesheets, and fonts.

Let's have a look at the most basic implementation using ASP.NET middleware.

```csharp
app.Use(async (context, next) => {
    context.Response.Headers.Add("Content-Security-Policy",
        "script-src 'self' cdn.jsdelivr.net;" +
        "style-src 'self' fonts.googleapis.com cdn.jsdelivr.net;" +
        "font-src 'self' fonts.gstatic.com;"
    );

    await next();
});
```

This implementation is simple, but it might be difficult to read and maintain when the amount of elements is increased.

To solve this problem we can use [NetEscapades.AspNetCore.SecurityHeaders](https://github.com/andrewlock/NetEscapades.AspNetCore.SecurityHeaders) package. The package is quite useful and can help to work with different security headers, not only with CSP. The code above can be transformed.

```csharp
var policyCollection = new HeaderPolicyCollection()
    .AddContentSecurityPolicy(builder =>
    {
        builder.AddScriptSrc()
            .Self()
            .From("cdn.jsdelivr.net");

        builder.AddStyleSrc()
            .Self()
            .From("fonts.googleapis.com")
            .From("cdn.jsdelivr.net");

        builder.AddFontSrc()
            .Self()
            .From("fonts.gstatic.com");
    });

app.UseSecurityHeaders(policyCollection);
```

This code is better to read and most likely it is what you need in 99% of cases. The only problem here is we need to change the application code every time we need to modify headers. What goes with running the deployment pipeline and provisioning new updates just because of changes in a configuration. Usually, it is not a problem due to we don't need to perform such kinds of changes every week or month.

If in some cases you don't want to work with headers in the application code they can be applied through Web Application Firewall (WAF). There are both individual and part of cloud providers' services. I will show how to use WAF which is a part of Azure Front Door.

We have an assumption that Front Door is provisioned and all necessary configuration has been applied. If not please find more information on how to do it [here](https://learn.microsoft.com/en-us/azure/frontdoor/create-front-door-portal).

Open the Front Door profile and go to the menu `"Settings" -> "Rule sets"`.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1690824583932/1afc4429-c848-4194-8aac-b0b4bdf8dc55.jpeg align="center")

On **Rule sets** page, click `Add` button to add new rule sets.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1690824781547/558b63ee-0143-45e7-a45c-f2e9bd47f01f.jpeg align="center")

The rule sets configuration page allows to add of various rules to customize HTTP requests. Let's add our rules for Content Security Policy. For that, we need to click `Add Rule` button.

Enter the descriptive name something like `cspRule`.

We skip adding conditions because we would like to apply CSP headers for each request.

The next step is to add an action to modify the response header. Click `Add an action` button and choose `Modify response header` from the menu.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1690825342442/628b66a1-89dd-413d-947f-98d4c0a59022.jpeg align="center")

Because we would like to set up CSP headers only through Frontdoor, it is better to take precautionary steps and clear all possible headers which might be set on the backend side. To do so we need to choose the `Delete` operator and as a header name enter `'Content-Security-Policy'`.

After that add 3 other `Append` actions with header name `'Content-Security-Policy'` and the following header values:

`script-src 'self' cdn.jsdelivr.net;`

`style-src 'self' fonts.googleapis.com cdn.jsdelivr.net;`

`font-src 'self' fonts.gstatic.com;`

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1690826588237/2af0d7ac-530e-4110-b401-d496a1d196da.jpeg align="center")

Click `Save` button.

Right now we have the ruleset with the rule to modify CSP headers what we need to do is to apply this ruleset to the route. To do so open `Front Door manager` and choose the route.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1690826854052/9c41905c-0de0-4141-8ffb-447f070e25f9.jpeg align="center")

There is a section "Rules" at the bottom of the page. Choose the earlier created ruleset and click `Update` button.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1690827041193/9956503c-512c-4ed4-aa5e-bfd08c714c23.jpeg align="center")

After all these steps Front Door will take care of applying the necessary Content Security Policy headers.

If you prefer to use IaC instead of working with UI there is the Bicep script for these rules.

```plaintext
resource frontdoor 'Microsoft.Cdn/profiles@2022-11-01-preview' = {
  name: 'sitefrontdoor'
  // The rest of configuration omitted
}

resource siteEndpoint 'Microsoft.Cdn/profiles/afdEndpoints@2021-06-01' = {
  parent: frontdoor
  name: 'siteEndpoint'
  // The rest of configuration omitted
}

resource cspRuleset 'Microsoft.Cdn/profiles/ruleSets@2022-11-01-preview' = {
  name: 'cspRuleset'
  parent: frontdoor
}

resource cspRule 'Microsoft.Cdn/profiles/ruleSets/rules@2022-11-01-preview' = {
  name: 'cspRule'
  parent: cspRuleset
  properties: {
    order: 1
    // We would like to apply this rule to all requests thus there are no conditions
    conditions: []
    actions: [
      // As a first action delete all CSP headers that might have set on backend site.
      // It is mostly precautions to make sure that we set headers only through Frontdoor.
      {
        name: 'ModifyResponseHeader'
        parameters: {
          headerAction: 'Delete'
          headerName: 'Content-Security-Policy'
          typeName: 'DeliveryRuleHeaderActionParameters'
        }
      }
      {
        name: 'ModifyResponseHeader'
        parameters: {
          headerAction: 'Append'
          headerName: 'Content-Security-Policy'
          typeName: 'DeliveryRuleHeaderActionParameters'
          value: 'script-src \'self\' cdn.jsdelivr.net;'
        }
      }
      {
        name: 'ModifyResponseHeader'
        parameters: {
          headerAction: 'Append'
          headerName: 'Content-Security-Policy'
          typeName: 'DeliveryRuleHeaderActionParameters'
          value: 'style-src \'self\' fonts.googleapis.com cdn.jsdelivr.net;'
        }
      }
      {
        name: 'ModifyResponseHeader'
        parameters: {
          headerAction: 'Append'
          headerName: 'Content-Security-Policy'
          typeName: 'DeliveryRuleHeaderActionParameters'
          value: 'font-src \'self\' fonts.gstatic.com;'
        }
      }
    ]
  }
}

resource siteRoute 'Microsoft.Cdn/profiles/afdendpoints/routes@2021-06-01' = {
  parent: siteEndpoint
  name: 'siteRoute'
  properties: {
    ruleSets: [
      {
        id: cspRuleset.id
      }
    ]
    // The rest of configuration omitted
  }
}
```

Image credits: "[right arrow sign on wall](https://unsplash.com/photos/MAgPyHRO0AA)" by [Nik](https://unsplash.com/@helloimnik)
