diff --git a/UPDATING.md b/UPDATING.md index 41a120f3107..432af7af4df 100644 --- a/UPDATING.md +++ b/UPDATING.md @@ -34,6 +34,7 @@ assists people when migrating to a new version. ### Breaking Changes +- [24262](https://github.com/apache/superset/pull/24262): Enabled `TALISMAN_ENABLED` flag by default and provided stricter default Content Security Policy - [24415](https://github.com/apache/superset/pull/24415): Removed the obsolete Druid NoSQL REGEX operator. - [24423](https://github.com/apache/superset/pull/24423): Removed deprecated APIs `/superset/slice_json/...`, `/superset/annotation_json/...` - [24400](https://github.com/apache/superset/pull/24400): Removed deprecated APIs `/superset/recent_activity/...`, `/superset/fave_dashboards_by_username/...`, `/superset/fave_dashboards/...`, `/superset/created_dashboards/...`, `/superset/user_slices/`, `/superset/created_slices/...`, `/superset/fave_slices/...`, `/superset/favstar/...`, diff --git a/docs/docs/security.mdx b/docs/docs/security.mdx index 56e058e5815..c2b3c72eae5 100644 --- a/docs/docs/security.mdx +++ b/docs/docs/security.mdx @@ -181,7 +181,7 @@ a certain resource type or policy area. You can check possible directives It's extremely important to correctly configure a Content Security Policy when deploying Superset to prevent many types of attacks. Superset provides two variables in `config.py` for deploying a CSP: -- `TALISMAN_ENABLED` defaults to `False`; set this to `True` in order to implement a CSP +- `TALISMAN_ENABLED` defaults to `True`; set this to `False` in order to disable CSP - `TALISMAN_CONFIG` holds the actual the policy definition (*see example below*) as well as any other arguments to be passed to Talisman. @@ -192,10 +192,20 @@ this warning using the `CONTENT_SECURITY_POLICY_WARNING` key in `config.py`. #### CSP Requirements -* Superset needs both the `'unsafe-eval'` and `'unsafe-inline'` CSP keywords in order to operate. +* Superset needs the `style-src unsafe-inline` CSP directive in order to operate. ``` - default-src 'self' 'unsafe-eval' 'unsafe-inline' + style-src 'self' 'unsafe-inline' + ``` + +* Only scripts marked with a [nonce](https://content-security-policy.com/nonce/) can be loaded and executed. +Nonce is a random string automatically generated by Talisman on each page load. +You can get current nonce value by calling jinja macro `csp_nonce()`. + + ``` + ``` * Some dashboards load images using data URIs and require `data:` in their `img-src` @@ -211,21 +221,11 @@ this warning using the `CONTENT_SECURITY_POLICY_WARNING` key in `config.py`. connect-src 'self' https://api.mapbox.com https://events.mapbox.com ``` -This is a basic example `TALISMAN_CONFIG` that implements the above requirements, uses `'self'` to -limit content to the same origin as the Superset server, and disallows outdated HTML elements by -setting `object-src` to `'none'`. +* Other CSP directives default to `'self'` to limit content to the same origin as the Superset server. + +In order to adjust provided CSP configuration to your needs, follow the instructions and examples provided in +[Content Security Policy Reference](https://content-security-policy.com/) -```python -TALISMAN_CONFIG = { - "content_security_policy": { - "default-src": ["'self'", "'unsafe-inline'", "'unsafe-eval'"], - "img-src": ["'self'", "data:"], - "worker-src": ["'self'", "blob:"], - "connect-src": ["'self'", "https://api.mapbox.com", "https://events.mapbox.com"], - "object-src": "'none'", - } -} -``` #### Other Talisman security considerations @@ -234,15 +234,15 @@ of which `content_security_policy` is only one. Those can be found in the [Talisman documentation](https://pypi.org/project/flask-talisman/) under *Options*. These generally improve security, but administrators should be aware of their existence. -In particular, the default option of `force_https = True` may break Superset's Alerts & Reports +In particular, the option of `force_https = True` (`False` by default) may break Superset's Alerts & Reports if workers are configured to access charts via a `WEBDRIVER_BASEURL` beginning with `http://`. As long as a Superset deployment enforces https upstream, e.g., -through a loader balancer or application gateway, it should be acceptable to set this -option to `False`, like this: +through a loader balancer or application gateway, it should be acceptable to keep this +option disabled. Otherwise, you may want to enable `force_https` like this: ```python TALISMAN_CONFIG = { - "force_https": False, + "force_https": True, "content_security_policy": { ... ``` diff --git a/superset-frontend/packages/superset-ui-core/src/models/ExtensibleFunction.ts b/superset-frontend/packages/superset-ui-core/src/models/ExtensibleFunction.ts index 78901dd565b..5a247d751ed 100644 --- a/superset-frontend/packages/superset-ui-core/src/models/ExtensibleFunction.ts +++ b/superset-frontend/packages/superset-ui-core/src/models/ExtensibleFunction.ts @@ -22,9 +22,8 @@ */ export default class ExtensibleFunction extends Function { + // @ts-ignore constructor(fn: Function) { - super(); - // eslint-disable-next-line @typescript-eslint/no-unsafe-return, no-constructor-return return Object.setPrototypeOf(fn, new.target.prototype); } diff --git a/superset/config.py b/superset/config.py index d62003991a8..3334a559480 100644 --- a/superset/config.py +++ b/superset/config.py @@ -1363,12 +1363,42 @@ TEST_DATABASE_CONNECTION_TIMEOUT = timedelta(seconds=30) CONTENT_SECURITY_POLICY_WARNING = True # Do you want Talisman enabled? -TALISMAN_ENABLED = False +TALISMAN_ENABLED = True # If you want Talisman, how do you want it configured?? TALISMAN_CONFIG = { - "content_security_policy": None, - "force_https": True, - "force_https_permanent": False, + "content_security_policy": { + "default-src": ["'self'"], + "img-src": ["'self'", "data:"], + "worker-src": ["'self'", "blob:"], + "connect-src": [ + "'self'", + "https://api.mapbox.com", + "https://events.mapbox.com", + ], + "object-src": "'none'", + "style-src": ["'self'", "'unsafe-inline'"], + "script-src": ["'self'", "'strict-dynamic'"], + }, + "content_security_policy_nonce_in": ["script-src"], + "force_https": False, +} +# React requires `eval` to work correctly in dev mode +TALISMAN_DEV_CONFIG = { + "content_security_policy": { + "default-src": ["'self'"], + "img-src": ["'self'", "data:"], + "worker-src": ["'self'", "blob:"], + "connect-src": [ + "'self'", + "https://api.mapbox.com", + "https://events.mapbox.com", + ], + "object-src": "'none'", + "style-src": ["'self'", "'unsafe-inline'"], + "script-src": ["'self'", "'unsafe-inline'", "'unsafe-eval'"], + }, + "content_security_policy_nonce_in": ["script-src"], + "force_https": False, } # diff --git a/superset/initialization/__init__.py b/superset/initialization/__init__.py index 3d7d9817f78..93890371be6 100644 --- a/superset/initialization/__init__.py +++ b/superset/initialization/__init__.py @@ -613,7 +613,11 @@ class SupersetAppInitializer: # pylint: disable=too-many-public-methods # Talisman talisman_enabled = self.config["TALISMAN_ENABLED"] - talisman_config = self.config["TALISMAN_CONFIG"] + talisman_config = ( + self.config["TALISMAN_DEV_CONFIG"] + if self.superset_app.debug + else self.config["TALISMAN_CONFIG"] + ) csp_warning = self.config["CONTENT_SECURITY_POLICY_WARNING"] if talisman_enabled: diff --git a/superset/templates/appbuilder/general/widgets/base_list.html b/superset/templates/appbuilder/general/widgets/base_list.html index 3b376d243b1..e4ea2ed9ae6 100644 --- a/superset/templates/appbuilder/general/widgets/base_list.html +++ b/superset/templates/appbuilder/general/widgets/base_list.html @@ -56,7 +56,7 @@ {{ lib.render_pagination(page, page_size, count, modelview_name) }} {{ lib.render_set_page_size(page, page_size, count, modelview_name) }} - diff --git a/superset/templates/appbuilder/general/widgets/search.html b/superset/templates/appbuilder/general/widgets/search.html index 22c6b629c18..04d58d6d98e 100644 --- a/superset/templates/appbuilder/general/widgets/search.html +++ b/superset/templates/appbuilder/general/widgets/search.html @@ -44,7 +44,7 @@ - + {% endblock %} {% block tail_js %} {{ super() }} diff --git a/superset/templates/superset/form_view/database_schemas_selector.html b/superset/templates/superset/form_view/database_schemas_selector.html index ac827c1330a..46ca3eb8742 100644 --- a/superset/templates/superset/form_view/database_schemas_selector.html +++ b/superset/templates/superset/form_view/database_schemas_selector.html @@ -16,7 +16,7 @@ KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. #} - {% endmacro %} {% macro expand_encrypted_extra_textarea() %} - {% endmacro %} {% macro expand_server_cert_textarea() %} - {% endmacro %} diff --git a/superset/templates/superset/partials/asset_bundle.html b/superset/templates/superset/partials/asset_bundle.html index 066c9f64e6d..60bc9aa2f83 100644 --- a/superset/templates/superset/partials/asset_bundle.html +++ b/superset/templates/superset/partials/asset_bundle.html @@ -21,7 +21,7 @@ with development version #} {% for entry in js_manifest(filename) %} - + {% endfor %} {% endmacro %} diff --git a/superset/templates/superset/theme.html b/superset/templates/superset/theme.html index 856796a4c4b..7fb29fc968f 100644 --- a/superset/templates/superset/theme.html +++ b/superset/templates/superset/theme.html @@ -1340,7 +1340,15 @@ {% endblock %} {% block tail_js %} {{ super() }} - - - + + + {% endblock %}