plotly / plotly.js

Open-source JavaScript charting library behind Plotly and Dash
https://plotly.com/javascript/
MIT License
17.05k stars 1.86k forks source link

Security warning: avoid using function constructor. #897

Closed feugy closed 2 years ago

feugy commented 8 years ago

I recently discovered that one of plotly.js's dependency is using Function constructor. Unfortunately, I can't tell exactly which one, but the code doesn't seems to belong to plotly itself.

Here is Chrome's error message:

plotly.js:74222Uncaught EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is
 not an allowed source of script in the following Content Security Policy directive: "script-src 'self'
 www.google-analytics.com ajax.googleapis.com 'nonce-67df8dace6ea7feb57cab73e41ebe0c7'".

makeOp  @   plotly.js:74222
(anonymous function)    @   plotly.js:74244
455.cwise-compiler  @   plotly.js:74271
s   @   plotly.js:7
(anonymous function)    @   plotly.js:7
129.ndarray @   plotly.js:25687
s   @   plotly.js:7
(anonymous function)    @   plotly.js:7
138../lib/shaders   @   plotly.js:27330
s   @   plotly.js:7
(anonymous function)    @   plotly.js:7
798.../../constants/gl3d_dashes @   plotly.js:127609
s   @   plotly.js:7
(anonymous function)    @   plotly.js:7
800.../../constants/gl_markers  @   plotly.js:128154
s   @   plotly.js:7
(anonymous function)    @   plotly.js:7
15.../src/traces/scatter3d  @   plotly.js:355
s   @   plotly.js:7
(anonymous function)    @   plotly.js:7
12../bar    @   plotly.js:312
s   @   plotly.js:7
e   @   plotly.js:7
(anonymous function)    @   plotly.js:7
a   @   plotly.js:7
(anonymous function)    @   plotly.js:7
__webpack_require__ @   bootstrap 08e5224…:585
fn  @   bootstrap 08e5224…:109
(anonymous function)    @   svg-to-png.js:2
__webpack_require__ @   bootstrap 08e5224…:585
fn  @   bootstrap 08e5224…:109
(anonymous function)    @   commons.js:36658
__webpack_require__ @   bootstrap 08e5224…:585
fn  @   bootstrap 08e5224…:109
(anonymous function)    @   index.js:1
__webpack_require__ @   bootstrap 08e5224…:585
fn  @   bootstrap 08e5224…:109
(anonymous function)    @   bootstrap.js:9
__webpack_require__ @   bootstrap 08e5224…:585
fn  @   bootstrap 08e5224…:109
(anonymous function)    @   index.js:3
__webpack_require__ @   bootstrap 08e5224…:585
fn  @   bootstrap 08e5224…:109
(anonymous function)    @   index.js:8
__webpack_require__ @   bootstrap 08e5224…:585
webpackJsonpCallback    @   bootstrap 08e5224…:21
(anonymous function)    @   index.js:1

Function constructor is considered by browser's CSP as an equivalent of eval. Therefore, we can't setup a good Content Security Policy, unless we allow 'unsafe-eval' which is a whole in the policy itself.

It is possible to identify the faulty dependency, and maybe provide a workaround ?

rreusser commented 8 years ago

I think this is the line: https://github.com/scijs/cwise-compiler/blob/master/lib/compile.js#L351

cwise is a library that performs operations on ndarrays. It doesn't look like plotly uses the cwise browserify transform when bundling plotly.js, but I believe even the transformed version that does the parsing ahead of time still compiles an optimized version (i.e. new Function) at runtime.

Long story short, this is pretty central to what cwise does, so I'm not totally sure of a good workaround, unless there's a way to short-circuit the optimization and just perform naive operations on data.

Edit: more precisely, this looks like it might be coming from ndarray-ops, which is already transformed, but the problem remains the same. Looks like it's coming from here. That wouldn't be too hard to rewrite naively, but I'd be surprised if cwise didn't creep in somewhere else in the dependencies.

etpinard commented 8 years ago

It doesn't look like plotly uses the cwise browserify transform when bundling plotly.js,

The plotly build step doesn't explicitly list the cwise transform, but several of our dependencies have cwise listed in their respective package.json namely ndarray-fill, ndarray-wrap and gl-select-static (ref this script).

willemx commented 7 years ago

I'm also running into this problem. Can't run my (Meteor) app because of this. Is there a work-around maybe?

jacobq commented 6 years ago

When I tried to bring plotly.js into my Electron application (via ember-plotly-shim) it triggers a security warning. In fact, since I have a set a Content-Security-Policy per the recommendations, it does not run at all.

Would someone be willing to write some / point to some documentation that describes how to incorporate plotly w/o using a pipeline that evaluates strings as code?

unsafe-string-eval

fxfilmxf commented 6 years ago

Still seeing this as well. Hasn't been addressed at all.

etpinard commented 6 years ago

Nothing has changed since https://github.com/plotly/plotly.js/issues/897#issuecomment-244402532, so yes this hasn't been addressed at all :scream:

The problematic cwise transform is only used in gl3d and gl2d (excluding scattergl), so using one of the partial bundles that don't include these trace types would solve this issue. Better yet, bundling plotly.js yourself may do the trick.

fxfilmxf commented 6 years ago

Thanks for the advice! I'll take a look at that.

jtal commented 5 years ago

Does anyone have the CSP header they've used to keep security as tight as possible but still use plotly?

jacobq commented 5 years ago

@jtal

Does anyone have the CSP header they've used to keep security as tight as possible but still use plotly?

I recommend starting with the strictest options and gradually relaxing restrictions until your application functions properly. There may be other parts of your work that won't work when fully restricted. As an example only, here is one I have used (inside of an electron app): default-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; connect-src 'self'; img-src 'self' 'data:'; style-src 'self' 'unsafe-inline'

See MDN

anders-kiaer commented 4 years ago

Looks like the direct plotly.js dependencies today that make plotly.js dependent on cwise are:

Does anyone know if it is feasible for plotly.js to go away from these dependencies (any alternatives?) and/or modify the dependencies themselves to not use cwise?

The unsafe-eval requirement is unfortunately currently stopping us from being allowed to use plotly.js's variant of parallell coordinates, as it appears to be part of the gl2d bundle, which then looks to be indirectly requiring cwise, ref. https://github.com/plotly/plotly.js/issues/897#issuecomment-371968332.

etpinard commented 4 years ago

@anders-kiaer you may be interested in https://www.npmjs.com/package/plotly.js-gl2d-dist, you can install it using

npm install plotly.js-gl2d-dist

which has no dependencies.

anders-kiaer commented 4 years ago

Thanks @etpinard 🙂 Hmm, not sure if I understand, isn't the cwise dependency bundled into the gl2d dist? I tried using the dist from npm install plotly.js-gl2d-dist, and also what I think is the CDN equivalent, and got the same CSP block without 'unsafe-eval'. Tested using this Dash snippet:

import dash
import dash_html_components as html
from flask_talisman import Talisman

app = dash.Dash(
    __name__, external_scripts=["https://cdn.plot.ly/plotly-gl2d-latest.min.js"]
)

CSP = {
    "default-src": "'self'",
    "script-src": [
        "'self'",
        "https://cdn.plot.ly",
        # "'unsafe-eval'",
        "'sha256-jZlsGVOhUAIcH+4PVs7QuGZkthRMgvT2n0ilH6/zTM0='",
    ],
    "style-src": ["'self'", "'unsafe-inline'"],
}

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

app.layout = html.Span("Hello Dash!")

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

which when looking at the browser console gives a

EvalError: call to Function() blocked by CSP

unless 'unsafe-eval' is added. Searching through plotly-gl2d.js gives me 18 hits on Function(. The first hit looks to come from this line.

etpinard commented 4 years ago

My mistake. I thought you were worried about the "unsafe-eval" behavior of cwise when bundling your own custom bundle, not in the browser runtime.

Unfortunately, there's no easy way for us to simply replace cwise. This package can improve performance by a large amount.

etpinard commented 4 years ago

But, the basic, cartesian, geo, mapbox and finance partial bundles should be fine.

That is, bundles that include trace types other than gl3d, gl2d, scattergl and splom should pass the "unsafe-eval" checks.

alexcjohnson commented 4 years ago

FWIW I don't think it would be unreasonable to explore making an eval-free version of cwise - it's not the eval that gives it its speed, it's just using that to do codegen and reduce its own size. But at the end of the day I'd expect gzip means this codegen isn't even saving that many bytes over the wire... not a guarantee, but if someone wants to explore that we would certainly entertain it.

tdelmas commented 4 years ago

The current version 1.52.2 (https://raw.githubusercontent.com/plotly/plotly.js/v1.52.2/dist/plotly.js) uses Fonction in eval mode in those places:

archmoj commented 4 years ago

Looks like the direct plotly.js dependencies today that make plotly.js dependent on cwise are:

Does anyone know if it is feasible for plotly.js to go away from these dependencies (any alternatives?) and/or modify the dependencies themselves to not use cwise?

@anders-kiaer this is done in #4929 and #4930 and available in plotly.js >= v1.54.4

polx commented 4 years ago

We're still meeting the use of eval as a problem trying to integrate plotly.js within CryptPad. Using smaller ones as anders suggested (in https://github.com/plotly/plotly.js/issues/897#issuecomment-585315283 did not solve it for us).

A pity...

nicolaskruchten commented 4 years ago

@polx can you confirm this is happening with version 1.54.7 of plotly.js, and can you provide some context around what tool you're using that is complaining about this please? This issue has wandered all over the place since 2016 and we recently addressed parts of it but it's not clear what's outstanding. It might be helpful to create a new issue narrowly-scope to the problem you're seeing.

polx commented 4 years ago

Hello @nicolaskruchten , Yes, it was on 1.54.7. We've been trying to embed plotly renderings as one of the rendering "macros" for cryptpad code (https://cryptpad.fr/). Cryptpad aimst at very high security standard and thus requires CSP. If we deactivate CSP, then things load. If we activate CSP then I get the following having replaced the plotly with the non-minimized version.

    Uncaught EvalError: call to Function() blocked by CSP
    makeOp http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:60786
    [443]</< http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:60808
    [443]< http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:60835
    o http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:7
    o http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:7
    [253]< http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:41713
    o http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:7
    o http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:7
    [266]< http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:44060
    o http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:7
    o http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:7
    [1164]< http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:190058
    o http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:7
    o http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:7
    [1166]< http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:190689
    o http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:7
    o http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:7
    [36]< http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:614
    o http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:7
    o http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:7
    [26]< http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:420
    o http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:7
    r http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:7
    <anonymous> http://localhost:3000/lib/plotly-latest.min.js?ver=3.20.1-1596722563915:7
    execCb http://localhost:3001/bower_components/requirejs/require.js?ver=2.3.5:1696

Does it help?

Paul

urnansbald commented 4 years ago

@anders-kiaer this is done in #4929 and #4930 and available in plotly.js >= v1.54.4

I'm also still experiencing this eval error with v1.54.7 @nicolaskruchten both pages are HTML and one is using the CDN and the other one has v1.54.7 in a Githubissues.

  • Githubissues is a development platform for aggregating issues.