【问题标题】:How to let script to use setAttribute 'style' without breaking CSP如何让脚本在不破坏 CSP 的情况下使用 setAttribute 'style'
【发布时间】:2017-11-20 09:25:36
【问题描述】:

我正在努力使我的 CSP 政策尽可能严格。我需要在我的捆绑包中包含 3d 派对组件。但它使用element.setAttribute('style'...) 方法破坏了CSP。有没有办法让这个特定的脚本以这种方式内联样式?

【问题讨论】:

  • 你可以自己清理它,使用正则表达式检查脚本元素等等
  • 我可以这样解决,但是我怕冻结一个3d派对组件。将来没有办法更新它。我仍然希望有可能用“nonce”属性或类似的东西来修复它。
  • Google reCAPTCHA 是执行此操作的一个常见来源。在stackoverflow.com/questions/44512798/…查看相关答案
  • 许多第 3 方库的样式设置不正确,我不得不“修复”其中许多以供我们自己使用,因为原作者懒得自己动手(即使被问到) .很烦人,但是除非您能找到更好的替代 3rd 方库,否则需要对其进行编辑以与您的 CSP 一起使用。

标签: javascript frontend content-security-policy


【解决方案1】:

是的,有办法。

这里有很多讨论:https://github.com/w3c/webappsec-csp/issues/212

最后总结得很简洁:

在解析时检查 CSP 并阻止解析样式属性。任何直接操作都会进行。

使用setAttribute 调用HTML 解析器并触发CSP。

所以,而不是:

.setAttribute("style","background:red"); // needs HTML parsing

你需要:

.style.background = "red"; // direct manipulation

一种方法有效而另一种无效,这听起来很奇怪,我认为这里的理解是 HTML 属性和 DOM 属性之间存在细微差别。 https://joji.me/en-us/blog/html-attribute-vs-dom-property/

【讨论】:

  • 关于 jquery:在 jquery 中使用 .css() 是通过 .style.name = 方法设置样式,因此它也可以绕过 CSP。这有利于构建您自己的元素操作脚本。
【解决方案2】:

2018-10-06 更新

这里的原始答案仍然是正确的现在 - 因为至少使用 CSP目前在浏览器中实现,仍然没有办法动态注入样式指定unsafe-inline 和指定unsafe-inline 基本上否定了CSP 的全部目的。

然而,CSP3 添加了一个新的unsafe-hashes 表达式,使您能够允许特定的内联脚本/样式。见https://w3c.github.io/webappsec-csp/#unsafe-hashes-usage,见Explainer: ‘unsafe-hashes’, ‘unsafe-inline-attributes’ and CSP directive versioning。不过,它还没有在任何浏览器中发布。所以目前,下面的答案仍然完全适用。


允许style 属性的唯一方法是使用unsafe-inlinestyle 属性是来自不同的来源还是来自 self 并不重要——除非您有 unsafe-inline,否则它们仍将被视为 CSP 违规。

具体来说,不会style 属性起作用的一种解决方案是使用随机数或散列——因为在 CSP 中,随机数和散列的使用仅针对 style 和 @987654334 定义@元素;该规范有一个Hash usage for style elements 部分,明确省略了为样式属性定义哈希使用。

因此,即使您在策略中为 style 属性的内容指定了正确的哈希值,您的浏览器仍会将其视为违规处理。

底线是,因为unsafe-inline 是允许style 属性的唯一方法——但使用unsafe-inline 几乎完全违背了使用任何 CSP 策略的目的——这是来自 CSP 的唯一安全解决方案透视就是永远不要使用style 属性——既不是直接来自您自己的标记/代码,也不是通过任何第三方代码。

【讨论】:

    【解决方案3】:

    对于任何寻找 jQuery 补丁来更改设置样式属性以设置正确 css 值的人,这是我使用的一个(来自 this Github,但修复了一个重要的错误以使其正常工作):

    var native = jQuery.attr;
    jQuery.attr = function (element, attr, value) {
        if (attr === 'style') {
            resetStyles(element);
            return applyStyles(element, value);
        } else {
            //native.apply(jQuery, arguments);
            return native(element, attr, value);
        }
    };
    
    function applyStyles(element, styleString) {
        if (styleString) {
            var styles = styleString.split(';');
            styles.forEach(function (styleBit) {
                var parts = styleBit.split(':');
                var property, value;
                if (parts.length === 2) {
                    property = parts[0].trim();
                    value = parts[1].trim();
    
                    element.style[property] = value;
                }
            });
            return styleString;
        }
    }
    
    function resetStyles(element) {
        var styleList = [].slice.call(element);
        styleList.forEach(function (propertyName) {
            element.style.removeProperty(propertyName);
        });
    }
    

    【讨论】:

    • 无论你是谁,我都爱你。谢谢
    【解决方案4】:

    奇怪的是为什么“3 岁”的问题出现在新的问题中,为什么 topicstarter 的问题仍未解决。

    使用little hack 可以轻松解决使用element.setAttribute('style', ...) 而不导致违反CSP 的问题,该little hack 将有问题的element.setAttribute('style') 全局替换为安全element.style.ptop = '...'。之后你可以在不破坏 CSP 的情况下使用setAttribute('style'),这也将修复 jQuery 和其他库。

    仅使用 CSP 本身的解决方案将无效,因为:

    • 并非所有浏览器都支持'unsafe-hashes' 令牌。
    • 对于通过'setAttribute('style')' 主动使用动态样式的第三方JavaScript 库而言,在技术上不可能维护数十个哈希的列表。此外,CSP 标头的大小有限。

    cakeboeing727 started在正确的轨道上,可惜新贡献者的想法没有被社会听到。可惜了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-10
      • 1970-01-01
      • 2011-02-05
      • 1970-01-01
      • 2010-12-21
      • 1970-01-01
      相关资源
      最近更新 更多