-
-
Notifications
You must be signed in to change notification settings - Fork 146
Inline CSS vs. build to separate CSS file #752
Comments
We also got this request a while ago for plotly.js plotly/plotly.js#2355 - and at least there it seems like there's a theoretical solution by converting from styles to presentation attributes, since it's SVG. Here and in dash-table we don't have that option, but I guess most use cases - assuming we were to pull the hardcoded inline styles out of this package and into style sheets - could be handled by users via classes and their own style sheets. I have to say though I just don’t get what the attack vector is. I understand from reading your link how after malicious CSS is on the page there’s a problem. I just don’t see how an attacker would inject their own CSS into the page, and how preventing inline styles guards against this injection. Can you provide any more information about this? |
Thanks for your reply @alexcjohnson
I'm not an expert on this matter, but can try. Typical attack vectors I guess would be the same as for JavaScript cross-site scripting (XSS), including both non-persistent (reflected) and persistent (stored) XXS. The former typically being triggered by a malicious user sending a specially crafted URL by e.g. e-mail to the victim, or through social engineering. The latter by the attacker being able to store malicious user input on the server which is later rendered for all other users of the app (typical example here is e.g. a forum / discussion board). Both these attack vectors rely on some code in the application not (correctly) sanitizing user input. In a perfect setting where all user input is sanitized correctly/safely, disallowing inline JavaScript and CSS using CSP would not make a big difference from a security point of view (if at all). However, in a complex (Dash) web app, this could be hard to guarantee. Especially with a growing pool of community provided Dash components. It is potentially enough that one community provided component is used, which e.g. changes inline style based on some non-sanitized user provided input. Inline Being able to set strict CSP settings, including disabling inline
Even when disallowing inline style through CSP you can set individual style attributes dynamically on elements: document.getElementById("some_id").style.backgroundColor = "green"; Not sure if that is enough for import dash
import dash_html_components as html
from flask_talisman import Talisman
app = dash.Dash(__name__)
csp = {
"default-src": "'self'",
"script-src": [
"'self'",
"'sha256-jZlsGVOhUAIcH+4PVs7QuGZkthRMgvT2n0ilH6/zTM0='",
]
}
Talisman(app.server, content_security_policy=csp, force_https=False)
app.layout = html.Div(id="some_id", children=["Hello Dash!"])
if __name__ == "__main__":
app.run_server() and then in the browser console run that single line of JavaScript. However running e.g. document.getElementById("some_id").setAttribute("style", "font-size: 200%"); in the console will be blocked by CSP since the style attribute is set directly (another example in this SO post). Probably because it resembles inline style tags Looks like with Some more references:
|
Thanks @anders-kiaer - makes a lot more sense to me now.
That makes this all a lot more manageable! If D3 is implemented in a compatible way as well, that would make the plotly.js variant much more tractable too. |
Sounds good @alexcjohnson. Yes, the d3.select("#some_id").style("background-color", "green") should be ~equivalent to document.getElementById("some_id").style.setProperty("background-color", "green") which as expected is also valid in a strict CSP setting (I double checked now using the Dash example above). |
CSP (Content Security Policy) is a good tool for enhancing security of web applications. Mozilla Observatory is a good place to check for CSP implementation across web applications. How easy it is to enforce strict CSP settings depends, to a large degree, on the frameworks used in the stack.
Dash out of the box is quite CSP settings friendly, e.g. you can do
pip install dash flask-talisman
(alternatively set the CSP headers directly instead of using flask-talisman) and then run e.g.This will work with no CSP errors on localhost in the browser console - despite quite strict CSP settings.
If however
import dash_core_components as dcc
is added, you will need to either addor
to the
CSP
dictionary in order to allow the CSS thatdcc
is adding inline to the app.The first is not optimal as you then again open for inline CSS "XSS" (as when not using CSP at all). The second is not optimal either as the hashes will need to update each time a new version of
dcc
changes its inline style content.If
dcc
could output CSS as a separate file during build, instead of inline style, we could with Dash also enforce strict CSS CSP. I.e. usemini-css-extract-plugin
instead ofstyle-load
inwebpack.config.js
during (production?) build ofdcc
.The text was updated successfully, but these errors were encountered: