Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DashRenderer initialization and CSP #630

Closed
anders-kiaer opened this issue Mar 5, 2019 · 10 comments · Fixed by #1371
Closed

DashRenderer initialization and CSP #630

anders-kiaer opened this issue Mar 5, 2019 · 10 comments · Fixed by #1371

Comments

@anders-kiaer
Copy link
Contributor

Dash is a CSP friendly framework, enabling writing XSS safe applications, however this had a setback in #367.

With pip install 'dash==0.38.0' dash_html_components flask-talisman you could test quite strict CSP settings in Dash locally with success:

import dash
import dash_html_components as html
from flask_talisman import Talisman

app = dash.Dash(__name__)
app.css.config.serve_locally = True
app.scripts.config.serve_locally = True

csp = {
       'default-src': '\'self\'',
       'script-src': '\'self\'',
       'style-src': '\'self\''
      }

Talisman(app.server, content_security_policy=csp, force_https=False)
app.layout = html.Div(children=['Hello Dash!'])

if __name__ == '__main__':
    app.run_server()

With dash==0.39.0 however this fails due to the new inline script

self.renderer = 'var renderer = new DashRenderer();'

A work-around could be to add hash of the current Dash generated inline script (sha256-jZlsGVOhUAIcH+4PVs7QuGZkthRMgvT2n0ilH6/zTM0=) to the server CSP script src headers, however that would be in need of update when the dash renderer string/configuration changes.

Not sure if it is feasible/fits the overall framework/plans, but could one suggestion be to follow the same concept as when the user e.g. wants to override the default favicon.ico (i.e. a file favicon.ico is placed in the assets folder - here in this case it could be e.g. a file dash-renderer-config.js). In addition to following the same concept in terms of overriding default assets and continue not having inline scripts in Dash core, it perhaps also better facilitates separation of Python- and JavaScript code.

@zmarwa
Copy link

zmarwa commented Mar 27, 2020

Hello, can you tell me please how can i create a hash for dash generated script? I use this lib as python package with django and CSP. Thks

@anders-kiaer
Copy link
Contributor Author

Not entirely sure what you mean with "dash generated script", but maybe this helps:

In our Dash based project, we use something along these lines to calculate CSP hashes for all inline scripts (the app.renderer inline script, as well as inline scripts due to clientside callbacks):

import hashlib
import base64
from typing import List

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
from flask_talisman import Talisman


def calculate_inline_hashes(app: dash.Dash) -> List[str]:
    """Given a Dash app instance, this function calculates
    CSP hashes (sha256 + base64) of all inline scripts, such that
    one of the biggest benefits of CSP (banning general inline scripts)
    can be utilized.

    Warning: Note that this function uses a "private" Dash app attribute,
    app._inline_scripts, which might change from one Dash version to the next.
    """
    return [
        f"'sha256-{base64.b64encode(hashlib.sha256(script.encode('utf-8')).digest()).decode('utf-8')}'"
        for script in [app.renderer] + app._inline_scripts
    ]


app = dash.Dash()

app.layout = html.Div(
    [dcc.Input(id="my-id", value="initial value", type="text"), html.Div(id="my-div")]
)


app.clientside_callback(
    """
    function(input) {
        return "You have entered: " + input;
    }
    """,
    Output(component_id="my-div", component_property="children"),
    [Input(component_id="my-id", component_property="value")],
)

csp = {
    "default-src": "'self'",
    "script-src": ["'self'"] + calculate_inline_hashes(app),
    "style-src": ["'self'", "'unsafe-inline'"],
}

Talisman(app.server, content_security_policy=csp, force_https=False)

if __name__ == "__main__":
    app.run_server(debug=True)

@zmarwa
Copy link

zmarwa commented Apr 15, 2020

Thks this help me!
Any way to keep
"style-src": ["'self'"] without using "'unsafe-inline'" please?

@anders-kiaer
Copy link
Contributor Author

anders-kiaer commented Apr 15, 2020

Any way to keep "style-src": ["'self'"] without using "'unsafe-inline'" please?

That very much depends on which components you use in your Dash application (e.g. dash alone does not require "'unsafe-inline'" wrt. style). If you on the other hand use dash-core-components this issue is related: plotly/dash-core-components#752

If you make your own Dash components, you can ensure you don't need "'unsafe-inline'" by providing static .css in a separate CSS-file (Dash has functionality for loading component provided .css files), and set dynamic CSS with JavaScript using a CSP compatible syntax (see the dcc issue above).

@p-mc2
Copy link

p-mc2 commented May 18, 2020

@anders-kiaer how are you dealing with dcc.graph() under this approach? Calculating CSP hashes appears to be working for everything except dcc.graph()

@anders-kiaer
Copy link
Contributor Author

anders-kiaer commented May 21, 2020

@anders-kiaer how are you dealing with dcc.graph() under this approach? Calculating CSP hashes appears to be working for everything except dcc.graph()

Not sure if you are talking about CSP hashes of inline CSS og JavaScript. I have not seen/had any problems with dcc.Graph and inline JavaScript. Inline CSS is discussed in the issue linked above, i.e. plotly/dash-core-components#752

@p-mc2
Copy link

p-mc2 commented May 21, 2020

@anders-kiaer how are you dealing with dcc.graph() under this approach? Calculating CSP hashes appears to be working for everything except dcc.graph()

Not sure if you are talking about CSP hashes of inline CSS og JavaScript. I have not seen/had any problems with dcc.Graph and inline JavaScript. Inline CSS is discussed in the issue linked above, i.e. plotly/dash-core-components#752

inline js, I'll re-explore the issue, what version of dash and dash-core-components are you on?

@rpmchale
Copy link

@PoSeyy I am also experiencing this issue. Are you still investigating this? I am using the following versions.

dash 1.12.0
dash-core-components 1.10.0

@p-mc2
Copy link

p-mc2 commented Jun 11, 2020

@rpmchale Couldn't solve this one, still interested in finding a solution, just not actively investigating.

@marcoaurelioguerrap
Copy link

@rpmchale is the dcc.graph that you are map?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants