【问题标题】:Secure way of inserting dynamic values in external JavaScript files在外部 JavaScript 文件中插入动态值的安全方法
【发布时间】:2014-01-29 21:33:41
【问题描述】:

我正在使用以下策略实现 Content Security Policy 标头

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

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

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

$(function() { 

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

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

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

C# 生成的 JavaScript

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

<script src="/script/Foo/bar"></script>

点击ScriptControllerFoo 操作,该操作返回text/javascript 类型的内容,插入动态值bar。这让我觉得这是一种可靠的方式,如果有点笨拙并且它首先破坏了使用 CSP 的一些优势(几乎就像没有 CSP 一样容易意外插入未编码的文本并导致XSS) .

隐藏的表单域

动态值被插入到页面中:

<input type="hidden" id="url" name="url" value"http:://www.example.com/" />

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

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

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

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

【问题讨论】:

    标签: c# javascript asp.net-mvc security content-security-policy


    【解决方案1】:

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

    是的,这通常不是一个好方法。 Razor 默认会进行 HTML 转义,但这里的上下文不仅仅是 HTML,它是:

    • 标识符,在里面
    • 内部的 CSS 选择器
    • 一个 JavaScript 字符串文字,在里面
    • 一个 JavaScript 语句,在里面
    • 一个 HTML CDATA 元素 (&lt;script&gt;)

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

    对于这个具体的例子来说,这可能不是很重要,假设GetFullHtmlFieldName 的结果总是安全的,但对于一般情况来说,这不是一个好的假设。

    C# 生成的 JavaScript:有点笨拙,并且有点破坏了使用 CSP 的一些优势

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

    同样生成 JavaScript 也不一定那么简单。 ASP 和 Razor 模板不会为您提供自动 JS 转义器。 JSON 编码几乎可以做到这一点,除了 JSON 和 JS 之间的细微差别(即 U+2028 和 U+2029)。

    隐藏的表单域

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

    使用隐藏表单字段时,您可能应该删除 name 属性,就好像它们在真正的 &lt;form&gt; 中一样,您通常实际上并不想提交您传递给 JS 的数据。

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

    <body data-mcefields="@Json.Encode(GetListOfHtmlFields())">
    ...
    var mce_array = $('body').data('mcefields');
    $.each(mce_array, function() {
        var element = document.getElementById(this);
        $(element).tinymce({ ... });
    });
    

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

    【讨论】:

    • 我完全同意你的第一点——这只是一个例子,看起来它可能是来自tinymce source 的潜在漏洞。我希望将所有内容都转换为外部 JS 并使用 CSP 将其锁定,而不是像那样修复每个单独的情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多