在外部JavaScript文件中插入动态值的安全方法

我正在使用以下策略实现内容安全策略标头

Content-Security-Policy: default-src 'self'

所以需要避免内联脚本,因为它不会执行。

但是,在MVC应用程序中,某些function(如编辑器模板)使用内联脚本。 例如tinymce_jquery_full.cshtml包含

 $(function() { $('#@ViewData.TemplateInfo.GetFullHtmlFieldName(string.Empty)').tinymce({ ... 

使用CSP时,在外部.js文件中包含动态值的好方法是什么?

我目前的想法是两种方式之一:

C#生成的JavaScript

类似于JSONP的工作方式,除了在URL中我没有指定回调 – 我只是传递动态值。 在每个需要动态JavaScript的文件中,我都包含一个链接,例如

  

它命中ScriptControllerFoo动作,它返回插入动态值bar text/javascript类型的内容。 这对我来说是一种可靠的方式,如果有点笨拙,它首先会破坏使用CSP的一些优点(几乎很容易意外地插入未编码的文本并导致XSS,因为它没有CSP)。

隐藏的表单字段

动态值将插入页面:

  

并在外部JavaScript文件中查找这些值:

 $('#url').val(); 

这将有效,但如果页面上有多个动态控件或者有多个相同类型的控件,则可能会很麻烦。 问题是如何有效地将每个.js脚本与其隐藏字段匹配。

有没有更好的解决方案,还是有任何我可以使用的现成框架?

$( ‘#@ ViewData.TemplateInfo.GetFullHtmlFieldName(的String.Empty)’)

是的,这不是一般的好方法。 Razor默认会HTML转义,但上下文不仅仅是HTML,它是:

  • 里面有一个标识符
  • 里面有一个CSS选择器
  • 里面有一个JavaScript字符串文字
  • 里面有一个JavaScript语句
  • HTML CDATA元素(

所以只是HTML转义是错误的 - 在选择器或JS字符串文字(如点,反斜杠,撇号,行分隔符......)的上下文中特殊的任何字符都会破坏这个语句。

也许这对于这个特定的例子来说并不是非常重要,假设GetFullHtmlFieldName的结果总是安全的,但对于一般情况来说这不是一个好的假设。

C#生成的JavaScript:有点笨拙,它有点挫败了使用CSP的一些优点

同意,避免这种情况。 获得正确的缓存并将生成页面内容的ASP中的信息传输到生成脚本的页面通常很痛苦。

生成JavaScript也不一定非常简单。 ASP和Razor模板不会为您提供自动JS转发器。 除了JSON和JS之间的琐碎差异(即U + 2028和U + 2029)之外,JSON编码几乎可以实现。

隐藏的表单字段

更一般地说,将信息放在DOM中。 隐藏的表单字段是一种方法; data-属性是另一种常用的属性。 无论哪种方式,我都非常喜欢DOM方法。

使用隐藏表单字段时,您应该删除name属性,就好像它们位于真正的

您通常不想提交传递给JS的数据。

这样,您可以使用常规默认的HTML转义将内容注入模板。 如果您需要更多结构,您始终可以对要传递的数据进行JSON编码。 在这种情况下,jQuery的data()帮助器也将自动为您提供JSON.parse

  ... var mce_array = $('body').data('mcefields'); $.each(mce_array, function() { var element = document.getElementById(this); $(element).tinymce({ ... }); }); 

(虽然......对于选择要应用HTML编辑器的元素的特定情况,也许更简单的方法就是使用class="tinymce"并应用$('.tinymce').tinymce(...) ?)