fix: Revert enabling CSP (#24476)

This commit is contained in:
Kamil Gabryjelski 2023-06-21 19:19:15 +02:00 committed by GitHub
parent d60040dbf7
commit fb08e0ecfc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 42 additions and 84 deletions

View File

@ -34,7 +34,6 @@ assists people when migrating to a new version.
### Breaking Changes ### 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. - [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/...` - [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/...`, - [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/...`,

View File

@ -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 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: prevent many types of attacks. Superset provides two variables in `config.py` for deploying a CSP:
- `TALISMAN_ENABLED` defaults to `True`; set this to `False` in order to disable CSP - `TALISMAN_ENABLED` defaults to `False`; set this to `True` in order to implement a CSP
- `TALISMAN_CONFIG` holds the actual the policy definition (*see example below*) as well as any - `TALISMAN_CONFIG` holds the actual the policy definition (*see example below*) as well as any
other arguments to be passed to Talisman. other arguments to be passed to Talisman.
@ -192,20 +192,10 @@ this warning using the `CONTENT_SECURITY_POLICY_WARNING` key in `config.py`.
#### CSP Requirements #### CSP Requirements
* Superset needs the `style-src unsafe-inline` CSP directive in order to operate. * Superset needs both the `'unsafe-eval'` and `'unsafe-inline'` CSP keywords in order to operate.
``` ```
style-src 'self' 'unsafe-inline' default-src 'self' 'unsafe-eval' '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()`.
```
<script nonce="{{ csp_nonce() }}">
/* my script */
</script>
``` ```
* Some dashboards load images using data URIs and require `data:` in their `img-src` * Some dashboards load images using data URIs and require `data:` in their `img-src`
@ -221,11 +211,21 @@ You can get current nonce value by calling jinja macro `csp_nonce()`.
connect-src 'self' https://api.mapbox.com https://events.mapbox.com connect-src 'self' https://api.mapbox.com https://events.mapbox.com
``` ```
* Other CSP directives default to `'self'` to limit content to the same origin as the Superset server. 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
In order to adjust provided CSP configuration to your needs, follow the instructions and examples provided in setting `object-src` to `'none'`.
[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 #### 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*. [Talisman documentation](https://pypi.org/project/flask-talisman/) under *Options*.
These generally improve security, but administrators should be aware of their existence. These generally improve security, but administrators should be aware of their existence.
In particular, the option of `force_https = True` (`False` by default) may break Superset's Alerts & Reports In particular, the default option of `force_https = True` may break Superset's Alerts & Reports
if workers are configured to access charts via a `WEBDRIVER_BASEURL` beginning 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., 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 keep this through a loader balancer or application gateway, it should be acceptable to set this
option disabled. Otherwise, you may want to enable `force_https` like this: option to `False`, like this:
```python ```python
TALISMAN_CONFIG = { TALISMAN_CONFIG = {
"force_https": True, "force_https": False,
"content_security_policy": { ... "content_security_policy": { ...
``` ```

View File

@ -22,8 +22,9 @@
*/ */
export default class ExtensibleFunction extends Function { export default class ExtensibleFunction extends Function {
// @ts-ignore
constructor(fn: Function) { constructor(fn: Function) {
super();
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, no-constructor-return // eslint-disable-next-line @typescript-eslint/no-unsafe-return, no-constructor-return
return Object.setPrototypeOf(fn, new.target.prototype); return Object.setPrototypeOf(fn, new.target.prototype);
} }

View File

@ -1363,42 +1363,12 @@ TEST_DATABASE_CONNECTION_TIMEOUT = timedelta(seconds=30)
CONTENT_SECURITY_POLICY_WARNING = True CONTENT_SECURITY_POLICY_WARNING = True
# Do you want Talisman enabled? # Do you want Talisman enabled?
TALISMAN_ENABLED = True TALISMAN_ENABLED = False
# If you want Talisman, how do you want it configured?? # If you want Talisman, how do you want it configured??
TALISMAN_CONFIG = { TALISMAN_CONFIG = {
"content_security_policy": { "content_security_policy": None,
"default-src": ["'self'"], "force_https": True,
"img-src": ["'self'", "data:"], "force_https_permanent": False,
"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,
} }
# #

View File

@ -613,11 +613,7 @@ class SupersetAppInitializer: # pylint: disable=too-many-public-methods
# Talisman # Talisman
talisman_enabled = self.config["TALISMAN_ENABLED"] talisman_enabled = self.config["TALISMAN_ENABLED"]
talisman_config = ( talisman_config = self.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"] csp_warning = self.config["CONTENT_SECURITY_POLICY_WARNING"]
if talisman_enabled: if talisman_enabled:

View File

@ -56,7 +56,7 @@
{{ lib.render_pagination(page, page_size, count, modelview_name) }} {{ lib.render_pagination(page, page_size, count, modelview_name) }}
{{ lib.render_set_page_size(page, page_size, count, modelview_name) }} {{ lib.render_set_page_size(page, page_size, count, modelview_name) }}
</div> </div>
<script language="javascript" nonce="{{ csp_nonce() }}"> <script language="javascript">
var modelActions = new AdminActions(); var modelActions = new AdminActions();
</script> </script>

View File

@ -44,7 +44,7 @@
</form> </form>
</div> </div>
<script nonce="{{ csp_nonce() }}"> <script>
(function($) { (function($) {
function checkSearchButton() { function checkSearchButton() {
var hasFilter = $('.filters tr').length; var hasFilter = $('.filters tr').length;

View File

@ -16,7 +16,7 @@
specific language governing permissions and limitations specific language governing permissions and limitations
under the License. under the License.
#} #}
<script nonce="{{ csp_nonce() }}"> <script>
window.onload = function() { window.onload = function() {
// See issue #7353, window.open fails // See issue #7353, window.open fails

View File

@ -16,7 +16,7 @@ KIND, either express or implied. See the License for the
specific language governing permissions and limitations specific language governing permissions and limitations
under the License. under the License.
#} #}
<script nonce="{{ csp_nonce() }}"> <script>
$('#delimiter').on('change', function () { $('#delimiter').on('change', function () {
var delimiterOptions = $('#delimiter').val(); var delimiterOptions = $('#delimiter').val();
if (delimiterOptions?.includes("other")) { if (delimiterOptions?.includes("other")) {

View File

@ -132,7 +132,7 @@
</div> </div>
{% endblock %} {% endblock %}
{% block add_tail_js %} {% block add_tail_js %}
<script src="{{url_for('appbuilder.static',filename='js/ab_keep_tab.js')}}" nonce="{{ csp_nonce() }}"></script> <script src="{{url_for('appbuilder.static',filename='js/ab_keep_tab.js')}}"></script>
{% endblock %} {% endblock %}
{% block tail_js %} {% block tail_js %}
{{ super() }} {{ super() }}

View File

@ -16,7 +16,7 @@ KIND, either express or implied. See the License for the
specific language governing permissions and limitations specific language governing permissions and limitations
under the License. under the License.
#} #}
<script nonce="{{ csp_nonce() }}"> <script>
var db = $("#database"); var db = $("#database");
var schema = $("#schema"); var schema = $("#schema");

View File

@ -17,7 +17,7 @@
under the License. under the License.
#} #}
{% macro testconn() %} {% macro testconn() %}
<script nonce="{{ csp_nonce() }}"> <script>
$("#sqlalchemy_uri").parent() $("#sqlalchemy_uri").parent()
.append('<button id="testconn" class="btn btn-sm btn-primary">{{ _("Test Connection") }}</button>'); .append('<button id="testconn" class="btn btn-sm btn-primary">{{ _("Test Connection") }}</button>');
$("#testconn").click(function(e) { $("#testconn").click(function(e) {
@ -72,19 +72,19 @@
{% endmacro %} {% endmacro %}
{% macro expand_extra_textarea() %} {% macro expand_extra_textarea() %}
<script nonce="{{ csp_nonce() }}"> <script>
$('#extra').attr('rows', '5'); $('#extra').attr('rows', '5');
</script> </script>
{% endmacro %} {% endmacro %}
{% macro expand_encrypted_extra_textarea() %} {% macro expand_encrypted_extra_textarea() %}
<script nonce="{{ csp_nonce() }}"> <script>
$('#encrypted_extra').attr('rows', '5'); $('#encrypted_extra').attr('rows', '5');
</script> </script>
{% endmacro %} {% endmacro %}
{% macro expand_server_cert_textarea() %} {% macro expand_server_cert_textarea() %}
<script nonce="{{ csp_nonce() }}"> <script>
$('#server_cert').attr('rows', '5'); $('#server_cert').attr('rows', '5');
</script> </script>
{% endmacro %} {% endmacro %}

View File

@ -21,7 +21,7 @@
with development version #} with development version #}
<!-- Bundle js {{ filename }} START --> <!-- Bundle js {{ filename }} START -->
{% for entry in js_manifest(filename) %} {% for entry in js_manifest(filename) %}
<script src="{{ entry }}" async nonce="{{ csp_nonce() }}"></script> <script src="{{ entry }}" async></script>
{% endfor %} {% endfor %}
<!-- Bundle js {{ filename }} END --> <!-- Bundle js {{ filename }} END -->
{% endmacro %} {% endmacro %}

View File

@ -1340,15 +1340,7 @@
{% endblock %} {% endblock %}
{% block tail_js %} {% block tail_js %}
{{ super() }} {{ super() }}
<script <script src="https://code.jquery.com/jquery-1.10.2.min.js"></script>
src="https://code.jquery.com/jquery-1.10.2.min.js" <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
integrity="sha256-C6CB9UYIS9UJeqinPHWTHVqh/E1uhG5Twh+Y5qFQmYg=" <script src="{{ assets_prefix }}/static/assets/stylesheets/less/cosmo/cosmoTheme.js"></script>
crossorigin="anonymous"
nonce="{{ csp_nonce() }}"></script>
<script
src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
crossorigin="anonymous"
nonce="{{ csp_nonce() }}"></script>
<script src="{{ assets_prefix }}/static/assets/stylesheets/less/cosmo/cosmoTheme.js" nonce="{{ csp_nonce() }}"></script>
{% endblock %} {% endblock %}