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

max*_*tor 6 javascript frontend content-security-policy

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

sid*_*ker 5

2018-10-06 更新

\n\n

这里的原始答案目前仍然正确\xe2\x80\x94 因为至少在浏览器中当前实现的CSP 中,\xe2\x80\x99s 仍然无法在不指定 和 的情况下动态注入unsafe-inline样式unsafe-inline基本上否定CSP 的全部目的。

\n\n

但是,CSP3 添加了一个新unsafe-hashes表达式,使您能够允许特定的内联脚本/样式。请参阅https://w3c.github.io/webappsec-csp/#unsafe-hashes-usage,并参阅解释器: \xe2\x80\x98unsafe-hashes\xe2\x80\x99, \xe2\x80\x98unsafe-inline- attribute\xe2\x80\x99 和 CSP 指令版本控制。不过,它还没有在任何浏览器中发布。所以暂时来说,下面的答案仍然完全适用。

\n\n
\n\n

允许style属性的唯一方法是使用unsafe-inline. style\xe2\x80\x99属性是否来自不同来源或来自\xe2\x80\x94并不重要,它们self\xe2\x80\x99 仍然会被视为 CSP 违规,除非您有unsafe-inline.

\n\n

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

\n\n

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

\n\n

底线是,因为这unsafe-inline是允许style属性 \xe2\x80\x94 的唯一方法,但使用unsafe-inline几乎完全违背了以 \xe2\x80\x94 开头的任何 CSP 策略的目的,从 CSP 角度来看,唯一安全的解决方案就是从不使用style切勿直接从您自己的标记/代码或通过任何第三方代码

\n


Lee*_*ski 5

是的,有办法。

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

最后简要总结一下:

CSP 在解析时检查并阻止解析样式属性。任何直接操作都要经过。

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

所以,而不是:

.setAttribute("style","background:red"); // needs HTML parsing
Run Code Online (Sandbox Code Playgroud)

你需要:

.style.background = "red"; // direct manipulation
Run Code Online (Sandbox Code Playgroud)

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


小智 5

对于任何寻找 jQuery 补丁来将样式属性设置更改为设置正确的 css 值的人,这里是我使用的一个(源自此 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);
    });
}
Run Code Online (Sandbox Code Playgroud)