How do I avoid Telerik KendoUI creating inline scripts when using ASP.NET MVC Kendo compontents?
The reason for avoiding inline scripts is to adhere by CSP header
Content-Security-Policy: script-src 'self' 'unsafe-eval' https://kendo.cdn.telerik.com
And not to get errors like
Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' 'unsafe-eval' https://kendo.cdn.telerik.com".
Is there a way to remove the kendo generated inline scripts or attach Content Security Policy nonce / sha256 to the scripts?
Simple Example (KendoUI Menu)
cshtml
@(Html.Kendo().Menu()
.Name("nav-menu")
.Items(items =>
{
items.Add().Text("Home").Action("Index", "Overview");
})
)
Browser html
<ul class="k-widget k-reset k-header k-menu k-menu-horizontal" id="nav-menu" data-role="menu" tabindex="0" role="menubar" aria-activedescendant="nav-menu_mn_active">
<li class="k-item k-state-highlight k-state-default k-first" role="menuitem">
<a class="k-link" href="/">Home</a>
</li>
</ul>
<script>
jQuery(function(){jQuery("#nav-menu").kendoMenu({});});
</script>
Solution
After the answer from @dimodi I ended up using nonce on kendo deferred initialization scripts.
Source: CSP Nonces in ASP.NET
cshtml
@(Html.Kendo().Menu()
.Name("nav-menu")
.Items(items =>
{
items.Add().Text("Home").Action("Index", "Overview");
})
.Deferred()
)
<script type="text/javascript" nonce="@Html.ScriptNonce()">
@Html.Kendo().DeferredScripts(false)
</script>
Startup.cs
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
app.Use((context, next) =>
{
var rng = new RNGCryptoServiceProvider();
var nonceBytes = new byte[32];
rng.GetBytes(nonceBytes);
var nonce = Convert.ToBase64String(nonceBytes);
context.Set("ScriptNonce", nonce);
context.Response.Headers.Add("Content-Security-Policy",
new[] {$"script-src 'self' 'unsafe-eval' https://kendo.cdn.telerik.com 'nonce-{nonce}';"
});
return next();
});
}
}
public static class NonceHelper
{
public static IHtmlString ScriptNonce(this HtmlHelper helper)
{
var owinContext = helper.ViewContext.HttpContext.GetOwinContext();
return new HtmlString(owinContext.Get<string>("ScriptNonce"));
}
}