Skip to content

DashRenderer initialization and CSP #630

Closed

Description

@anders-kiaer

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.

Activity

  1. zmarwa commented on Mar 27, 2020

    @zmarwa

    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

  2. anders-kiaer commented on Mar 28, 2020

    @anders-kiaer
    ContributorAuthor

    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)
  3. zmarwa commented on Apr 15, 2020

    @zmarwa

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

  4. anders-kiaer commented on Apr 15, 2020

    @anders-kiaer
    ContributorAuthor

    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).

  5. p-mc2 commented on May 18, 2020

    @p-mc2

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

  6. anders-kiaer commented on May 21, 2020

    @anders-kiaer
    ContributorAuthor

    @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

  7. p-mc2 commented on May 21, 2020

    @p-mc2

    @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?

  8. rpmchale commented on Jun 11, 2020

    @rpmchale

    @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

  9. p-mc2 commented on Jun 11, 2020

    @p-mc2

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

  10. marcoaurelioguerrap commented on Oct 22, 2022

    @marcoaurelioguerrap

    @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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions