I'm working on an application that has a strict CSP policy including style-src, which prevents the possibility of using inline styles. If I attempt to use React's builtin CSS templater with the following component, the styling is blocked with an error.
class SomeComponent extends React.Component {
constructor() {
super();
this.styles = {
backgroundColor: 'red',
color: 'blue',
};
}
render() {
return <div ref="someDiv" style={this.styles}>Some Component</div>;
}
}
DOM.render(<SomeComponent />, document.getElementById('main'));
Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'self'". Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce ('nonce-...') is required to enable inline execution.
I can get around this by manually manipulating the DOM's style object after every React render:
class SomeComponent extends React.Component {
constructor() {
super();
this.styles = {
backgroundColor: 'red',
color: 'blue',
};
}
componentDidMount() {
_.extend(this.refs.someDiv.style, this.styles);
}
componentDidUpdate() {
_.extend(this.refs.someDiv.style, this.styles);
}
render() {
return <div ref="someDiv">Some Component</div>;
}
}
DOM.render(<SomeComponent />, document.getElementById('main'));
I'm wondering if React's DOM engine can set the style object instead of serializing to a string and inserting a style attribute in the markup? This would make React adhere more tightly to CSP.
Would a pull request on this be welcomed?
In its current form (0.14) React generates a string of markup in a single pass and then inserts it. Ultimately this is a single dom operation and historically has been faster. This goes for the style as well. Updates are applied individually.
In the next version we'll be using createElement instead of innerHTML but I think we still set initial style all together - not sure if that matters for csp since the element is already created at that point. Can you try a build from master and see if it works (http://react.zpao.com/builds/master/latest)
Also cc @spicyj in case he knows if we actually do set each style property individually on initial render (and if we should if we don't currently)
not sure if that matters for csp since the element is already created at that point.
Nah, the only way to bypass this stuff is to use the style props on the dom element directly elem.style.border = '1px solid blue';
(setStyle
api also works).
My gut is that it'd definitely be slower by a usually insignificant amount. Perhaps it'd be a good thing to be able to configure (or just bypass with rawStyle="exact string we'll inject into style attr"
).
Thus far to get around this, I've been a fan of solutions that allow you to write the inline-looking css, but still end up generating a class name and pushing the styles into an external file. This works well unless you have dynamic variable values that you'd like to modify on the fly.
We do set styles individually in master and it'll be in v15. Until then I suppose you'll need to add unsafe-inline
to style-src
.
Note that server rendering will still generate style="..."
markup by necessity.
As an interesting side note, HTML 5.2 supports
Most helpful comment
@sophiebits
Unfortunately that would make our React-powered sites vulnerable to clever attacks/injections, such as this CSS-only keylogger: https://no-csp-css-keylogger.badsite.io/
Do you believe that @xkr47's proposed solution above a good one, as it seems to be? Thanks.