November Happy Hour will be moved to Thursday December 5th.

RenderEPiServerQuickNavigator uses unsafe inline, how to add nonce?

Vote:
 

Hello guys,

i have a question regarding CSP unsafe-inline of RenderEPiServerQuickNavigator.

It renders script like this:

<link rel="stylesheet" type="text/css" href="/Util/styles/quicknavigator.css" />
<script type="text/javascript" src="/Util/javascript/quicknavigator.js"></script>
<script type="text/javascript">

                //<![CDATA[ 
                (function () { new epi.QuickNavigator({"menuItems":{"dashboard":{"caption":"Dashboard","url":"/Smarthouse","javascript":null,"enabledScript":"true","imageUrl":null},"editMode":{"caption":"CMS Edit","url":"/Smarthouse/CMS/?language=en#context=epi.cms.contentdata:///9","javascript":null,"enabledScript":"true","imageUrl":null}},"menuTitle":"Episerver","defaultUrl":""}); }()); 
                //]]>
</script>

How can i add a nonce value to the inline script to avoid csp violation? The only way i see is using string replace.

Pseudo code:

public static IHtmlString RenderEPiServerQuickNavigatorWithCspNonce(this HtmlHelper htmlHelper, string partialViewName = "QuickNavigator")
{
	if (PageEditing.PageIsInEditMode || !PathAccessChecker.HasEditAccess(PrincipalInfo.CurrentPrincipal) || ServiceLocator.Current.GetInstance<IDatabaseMode>().DatabaseMode == DatabaseMode.ReadOnly)
	{
		return htmlHelper.Raw(string.Empty);
	}
	QuickNavigatorMenu quickNavigatorMenu = new QuickNavigatorMenu();
	List<KeyValuePair<string, QuickNavigatorMenuItem>> quickNavigatorMenuProviders = 
		ServiceLocator.Current.GetAllInstances<IQuickNavigatorItemProvider>()
		.OrderBy(p => p.SortOrder)
		.SelectMany(provider => provider.GetMenuItems(quickNavigatorMenu.CurrentContentLink))
		.ToList();
	quickNavigatorMenuProviders.ForEach(item => quickNavigatorMenu.Items.Add(item));
	
	quickNavigatorMenu.RegisterRequiredResources();
	return ReplaceQuickNavigatorScriptWithNonceScript(htmlHelper.RequiredClientResources(partialViewName));
}

Regards,

Tim

#221125
Edited, Apr 14, 2020 8:18
Vote:
 

I have solved it in the "dirty" way above.

In case someone wants to know how, here's also the missing ReplaceQuickNavigatorScriptWithNonceScript which uses HtmlAgilityPack:

private static IHtmlString ReplaceQuickNavigatorScriptWithNonceScript(IHtmlString originalEpiServerScript)
{
	ICspConfiguration cspConfig = ServiceLocator.Current.GetInstance<ICspConfiguration>();
	if (!Feature<SwitchContentSecurityOptimizations>.Is().Enabled || !cspConfig.IsCspScriptNonceEnabled)
	{
		return originalEpiServerScript;
	}

	INonceProvider nonceProvider = ServiceLocator.Current.GetInstance<INonceProvider>();
	HtmlDocument doc = new HtmlDocument();
	doc.LoadHtml(originalEpiServerScript.ToHtmlString());
	IEnumerable<HtmlNode> relevantScriptTags = doc.DocumentNode.Descendants("script")
		.Where(script => script.Attributes["nonce"] == null &&
			(script.Attributes["src"] != null || !string.IsNullOrWhiteSpace(script.InnerText)));

	foreach (HtmlNode script in relevantScriptTags)
	{
		script.Attributes.Add("nonce", nonceProvider.CspScriptNonce);
	}

	return new HtmlString(doc.DocumentNode.OuterHtml);
}
#221246
Edited, Apr 15, 2020 16:11
* 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.