.netrazornoncecontent-security-policy

How to handle CSP nonce for usercentries? (uc-block.bundle.js)


I'm using CSP; I made the changes for the policy on the server side, and then I'm using the nonce on the client side. It works for everything. I just have an issue with UserCentries. I still get the below error:

uc-block.bundle.js:1 Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'self' 'nonce-cdbb69b0170fa85cd202dd223dc7de80' https://fonts.googleapis.com https://*.iadvize.com". Either the 'unsafe-inline' keyword, a hash ('sha256-gxqnKDxRDSXGSNnZ1pqKxuJyI+PHG6Tvsbz7z9B4+ZI='), or a nonce ('nonce-...') is required to enable inline execution.

And when I click on the error line in Chrome, it goes to the codes inside this file: enter image description here

It seems the issue is because of the style tag here, which doesn't have the nonce attribute.

I have a CspMiddleware and I handle the policy inside it. Here is the code for Policy:

public override async Task Invoke(IOwinContext context)
{
    var randomNonce = Shared.Extensions.Extensions.GenerateNonce();
    var isUmbracoRequest = context.Request.Uri.AbsolutePath.StartsWith("/umbraco");
    var policy = new[] {
        $"script-src 'self' {(isUmbracoRequest ? "'unsafe-inline'" : $"'nonce-{randomNonce}' 'strict-dynamic'")} {string.Join(" ", this._config?.ExternalUrls)}; " +
        $"style-src 'self' {(isUmbracoRequest ? "'unsafe-inline'" : $"'nonce-{randomNonce}'")} {string.Join(" ", this._config?.ExternalCssUrls)}; " +
        $"object-src 'self'; " +
        $"report-uri /umbraco/api/helper/CreateCSPReport"
    };

    if (!context.Response.Headers.ContainsKey("Content-Security-Policy")) context.Response.Headers.Add("Content-Security-Policy", policy);
    if (!context.Response.Headers.ContainsKey("X-Content-Security-Policy")) context.Response.Headers.Add("X-Content-Security-Policy", policy);
    if (!context.Response.Headers.ContainsKey("X-Webkit-CSP")) context.Response.Headers.Add("X-Webkit-CSP", policy);
    if (!isUmbracoRequest) context.Response.Headers.Add("X-Nonce", new[] { randomNonce });

    await Next.Invoke(context);
}

And on the razor page, I get the nonce and then set it for the UserCentries script:

@{
    var xNonce = HttpContext.Current.Response.Headers.GetValues("X-Nonce")?.First();
}

<script type="application/javascript" src="https://privacy-proxy.usercentrics.eu/latest/uc-block.bundle.js" nonce="@xNonce"></script>

When I inspect in the browser, I can see the nonce that has been added to this script, but still, I have the above error in the console. enter image description here

And here is how the CSP looks like in the http header: enter image description here

How can I handle the nonce for this specific script (uc-block.bundle.js)?

Thank you.


Solution

  • You can redefine the document.createElement function so that it not only creates the element, but also applies the nonce in case a style tag is being created, which is happening in that uc-block.bundle.js script.

    That custom document.createElement function needs to be set up before the uc-block.bundle.js gets loaded.

    Note that this is not without risk! Any referenced script marked with a nonce will be allowed to create an inline style element that will be executed.

    For testing purposes I used below CSP.

    script-src 'nonce-abc1234'; style-src 'nonce-abc1234'
    

    @{
      var xNonce = "abc1234";  
      // Get from http header.  
      // HttpContext.Current.Response.Headers.GetValues("X-Nonce")?.First();
    }
    <script nonce="@xNonce">
      document.createElement = (function(func) {
        return function() {
          var element = func.apply(this, arguments);
          if (element.tagName.toLowerCase() == "style") 
          {
            element.setAttribute("nonce", "@xNonce");
          }
          return element;
        };
      })(document.createElement);
    </script>
    
    <script type="application/javascript" 
            src="https://privacy-proxy.usercentrics.eu/latest/uc-block.bundle.js" 
            nonce="@xNonce"></script>
    

    The browsers developer tools shows that the style element has been added with a nonce (without revealing its value).

    enter image description here