如何让脚本在不破坏 CSP 的情况下使用 setAttribute 'style'

How to let script to use setAttribute 'style' without breaking CSP

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

2018-10-06更新

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

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


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

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

的哈希使用

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

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

是的,有办法。

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

最后简要总结:

CSP is checked at parsing and blocks parsing the style attribute. Any direct operations go through.

使用 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 补丁以将样式属性设置更改为设置正确 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);
    });
}

很奇怪为什么新的出现了'3岁'的问题,为什么topicstarter的问题还没有解决。

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

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

  • 'unsafe-hashes' 令牌仍未在所有浏览器中得到支持。
  • 对于通过“setAttribute('style')”主动使用动态样式的 third-party JavaScript 库,在技术上不可能维护包含数十个哈希的列表。此外,CSP headers 大小有限。

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