Search code examples
javascriptasp.net-mvckendo-uitelerikcontent-security-policy

How can I get KendoUI MVC to work with Content Security Policy


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"));
    }
}

Solution

  • You can control where the Kendo UI MVC inline scripts are rendered on the page, but cannot completely remove them. Actually, you can, but then the widgets will not initialize.

    Consider using the non-MVC Kendo UI widgets:

    http://docs.telerik.com/kendo-ui/aspnet-mvc/kendo-ui-vs-mvc-wrappers

    Vanilla HTML/JavaScript Kendo UI widgets provide full control over the placement of the initialization scripts - server wrappers render the widgets' initialization scripts right after the widget's HTML output. Even if you use deferred initialization, the scripts are still kept in the View. When using plain (non-wrapper) Kendo UI widgets, you write the initialization scripts yourself and can move them to external script files.

    Also keep in mind that Kendo UI templates rely on eval, which will also bring troubles if CSP is enabled.