SaaS CMS has officially launched! Learn more now.

CSP problems with inline AI script and Episerver QuickNavigator

EJ
EJ
Vote:
 

Hi,

We have implemented Content Security Policy for our site and boy what a cumbersome process. We have created a middleware that whitelists third party scripts and for inline-scripts we use nonce. But, Application Insights is injected inline and i cant add a nonce to that script and hence it will be blocked. 

Is there a way I can insert the AI script my self with a nonce valuje  instead of magically retrieving it from DXP?

Also, for the Episerver QuickNavigator addon, can i somehow find and add a nonce to this as well without using unsafe-inline which defeats the entire purpose of CSP. 

I've been struggling together with Github Copilot for a while now, not finding a solution. 

#322551
May 23, 2024 13:13
Vote:
 

Not sure how he's dealt with those issues, but maybe check out Mark Stott's Stott.Security.Optimizely add-on for inspiration?

https://world.optimizely.com/blogs/mark-stott/dates/2024/5/stott-security-version-2-so-far/

https://github.com/GeekInTheNorth/Stott.Security.Optimizely 

#322556
May 23, 2024 19:04
EJ - May 26, 2024 18:15
Hey Daniel, thanks. I looked at Stott.Security addon and I really loved it. It was a great and easy to add policies on the fly as the failed and so on.
Although, it did not give me enough freedom to customize the policies as I wanted them, so I ended up creating my own custom middleware. Inspired by Mark Stott.

But, in my project, I use services.AddApplicationInsightsTelemetry(); in the Startup.cs. And this, I think, inserts the AI-script tag into my html leaving me no control over it.
Vote:
 

I wish you well on your CSP journey :D

We 'catch' the output of the code that injects scripts and replace-in the nonce. 
So for the navigator we have this in our _Layout.cshtml:

@{
    var optiNav = (await Html.RenderEPiServerQuickNavigatorAsync()).InsertNonce();
}
@Html.Raw(optiNav)

And similarly we apply this to the header output of IClientResourceService to inject it for the AI script.

The InsertNonce method is a custom helper method that injects the nonce generated by the Jhoose security addon:

private static readonly Injected<ICspProvider> _cspProvider;

public static string InsertNonce(this IHtmlContent content)
{
    var nonceValue = _cspProvider.Service.GenerateNonce();

    var htmlString = GetHtmlString(content); // get raw html from IHtmlContent

    var result = htmlString
        .Replace(" nonce ", " ")
        .Replace(" nonce>", " >")
        .Replace("<script ", $"<script nonce=\"{nonceValue}\" ")
        .Replace("<script>", $"<script nonce=\"{nonceValue}\">");

    return result;
}

Open to a less awkward way of doing this. 

#322597
May 24, 2024 1:28
EJ - May 26, 2024 18:22
Hey Arjan, Haha, thanks! :)
So for it's been a semi-long and ardous journey.

Anyway, That looks like a nice way to solve the QuickNavigator-problem. Given our lack of control over the quicknavigator, i think this is a nice solution. I will try it tomorrow and give you an update.

Not sure how you solved the AI-scripts though. In our Optimizely solution, I think this is implemented in our startup.cs.
We use:
- services.AddApplicationInsightsTelemetry();
- services.AddCustomApplicationInsights();
Where that last one is a custom filtering applied to application insights. I do believe the AddApplicationInsightsTelemetry is the one responsible for adding the ai-script-tag into our html.
Arjan Paauw - May 27, 2024 0:45
AI is 'solved' in the same way, so in the header we have:
@Html.Raw(ClientResources.RenderAllRequiredResources("Header").InsertNonce())

BTW if that custom AI filtering is from my blog https://world.optimizely.com/blogs/arjanblog/dates/2023/7/finetuning-application-insights-in-cms12/
you should not have that first statement, it'll cause the second to be partially ignored as it also instantiates AI telemetry.
EJ - May 27, 2024 9:52
Thank you, Arjan! Yes, indeed, I looked at your blogpost for inspiration. I only use the AddApplicationInsightsTelemetry() once, i double checked :)
I confirmed that the QuickNavigator is working with correct nonce now. Thank you :) :)

So, a curious thing happens when I add my version of @Html.Raw(ClientResources.RenderAllRequiredResources("Header").InsertNonce()). It adds the script of the Application insights with the correct nonce, but it still injects a duplicate ai-script without the nonce which of course is rejected by my policy. What is going on :p
Is the order of placement of the "RenderAllRequiredResources" within the header-tag of importance, do you know?
Arjan Paauw - May 28, 2024 0:01
That's odd, maybe something somewhere is calling the RenderAllRequiredResources again?
EJ - Jun 03, 2024 5:45
Hi Arjan,
It turns out you are exactly right. I had a duplicate of RenderAllRequiredResources, sort of.
What fixed my issue in the end was a duplicate implementation of @Html.Raw(ClientResources.RenderAllRequiredResources("Header") that I didnt noticed because it was written slightly different: Html.RequiredClientResources(RenderingTags.Header). Removed that, and voilà, it worked as expected. Thanks again for your help :)
Will mark your answer as the correct one.
Arjan Paauw - Jun 03, 2024 5:51
Oh great you figured it out, these things can take so much time!
Vote:
 

If you add CSP,  you need to make sure to also enable it for client/template resources https://docs.developers.optimizely.com/content-management-system/docs/content-security-policy#bring-your-nonce 

#322766
Edited, May 28, 2024 9:10
Vote:
 

Hey EJ,

maybe it's not relevant but it doesn't harm to mention:
- do know that AppInsights could be added already through EPiServer.CloudPlatform.Cms -> AddCmsCloudPlatformSupport(), probably in your startup.cs
- there are scenarios where the app insights script is injected automatically. Mainly CMS 11 where it is controlled through the env variable APPINSIGHTS_JAVASCRIPT_ENABLED)

More info:
- https://docs.developers.optimizely.com/digital-experience-platform/docs/consumption-metrics#client-telemetry
- https://dev.to/gkarwchan/everything-you-need-to-know-about-telemetry-and-instrumentation-your-aspnet-application-on-azure-49jn

We needed to disable auto-injection (through opti support) as it injected the script in some static HTML files which broke some blazor web assembly functionality.

bye!

#322939
May 31, 2024 13:12
EJ - Jun 03, 2024 5:42
Hi Bob,
Thanks. I went down this path as well and can confirm that this actually worked as well for CMS 12. Support told me that they could disable APPINSIGHTS_CLIENTRESOURCE_ENABLED = False
APPINSIGHTS_JAVASCRIPT_ENABLED = Flase
And then I could insert the AppInsights script where I wanted. So this is a valid way of doing this. Thanks :)

What fixed my issue in the end was a duplicate implementation of @Html.Raw(ClientResources.RenderAllRequiredResources("Header") that I didnt noticed (Html.RequiredClientResources(RenderingTags.Header)).
- Jun 03, 2024 7:37
Hey, thanks for the update!
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.