Files
superset2/superset/assets/javascripts/dashboard/components/GridCell.jsx
David Dworken 4ff17ffc8d Fix 4 security vulnerabilities (#4390)
* Switched yaml.load to yaml.safe_load to prevent code execution via crafted yaml files

Python's yaml.laod can lead to code execution via crafted yaml files such as:

```
code_exec: !!python/object/apply:subprocess.check_output ['ls']
```

* Fixed XSS via bleach

It was possible to get an XSS via the markdown library via simply setting a description containing arbitary HTML tags.
It was also possible to create links that went to the `javascript:` link handler (eg `[example](javascript:alert(0)`)
Using bleach to sanitize it solves both of these.

* Added XFO header by default to prevent clickjacking attacks

Note that with this application clickjacking can be relatively severe via the SQLLab functionality
which allows executing arbitary SQL.

* Added justification for dangerouslySetInnerHTML

* Fixed linting errors

* Fixed linting errors
2018-02-09 14:33:29 -08:00

149 lines
4.6 KiB
JavaScript

/* eslint-disable react/no-danger */
import React from 'react';
import PropTypes from 'prop-types';
import SliceHeader from './SliceHeader';
import ChartContainer from '../../chart/ChartContainer';
import '../../../stylesheets/dashboard.css';
const propTypes = {
timeout: PropTypes.number,
datasource: PropTypes.object,
isLoading: PropTypes.bool,
isCached: PropTypes.bool,
cachedDttm: PropTypes.string,
isExpanded: PropTypes.bool,
widgetHeight: PropTypes.number,
widgetWidth: PropTypes.number,
exploreChartUrl: PropTypes.string,
exportCSVUrl: PropTypes.string,
slice: PropTypes.object,
chartKey: PropTypes.string,
formData: PropTypes.object,
filters: PropTypes.object,
forceRefresh: PropTypes.func,
removeSlice: PropTypes.func,
updateSliceName: PropTypes.func,
toggleExpandSlice: PropTypes.func,
addFilter: PropTypes.func,
getFilters: PropTypes.func,
clearFilter: PropTypes.func,
removeFilter: PropTypes.func,
editMode: PropTypes.bool,
annotationQuery: PropTypes.object,
};
const defaultProps = {
forceRefresh: () => ({}),
removeSlice: () => ({}),
updateSliceName: () => ({}),
toggleExpandSlice: () => ({}),
addFilter: () => ({}),
getFilters: () => ({}),
clearFilter: () => ({}),
removeFilter: () => ({}),
editMode: false,
};
class GridCell extends React.PureComponent {
constructor(props) {
super(props);
const sliceId = this.props.slice.slice_id;
this.addFilter = this.props.addFilter.bind(this, sliceId);
this.getFilters = this.props.getFilters.bind(this, sliceId);
this.clearFilter = this.props.clearFilter.bind(this, sliceId);
this.removeFilter = this.props.removeFilter.bind(this, sliceId);
}
getDescriptionId(slice) {
return 'description_' + slice.slice_id;
}
getHeaderId(slice) {
return 'header_' + slice.slice_id;
}
width() {
return this.props.widgetWidth - 10;
}
height(slice) {
const widgetHeight = this.props.widgetHeight;
const headerId = this.getHeaderId(slice);
const descriptionId = this.getDescriptionId(slice);
const headerHeight = this.refs[headerId] ? this.refs[headerId].offsetHeight : 30;
let descriptionHeight = 0;
if (this.props.isExpanded && this.refs[descriptionId]) {
descriptionHeight = this.refs[descriptionId].offsetHeight + 10;
}
return widgetHeight - headerHeight - descriptionHeight;
}
render() {
const {
exploreChartUrl, exportCSVUrl, isExpanded, isLoading, isCached, cachedDttm,
removeSlice, updateSliceName, toggleExpandSlice, forceRefresh,
chartKey, slice, datasource, formData, timeout, annotationQuery,
} = this.props;
return (
<div
className={isLoading ? 'slice-cell-highlight' : 'slice-cell'}
id={`${slice.slice_id}-cell`}
>
<div ref={this.getHeaderId(slice)}>
<SliceHeader
slice={slice}
exploreChartUrl={exploreChartUrl}
exportCSVUrl={exportCSVUrl}
isExpanded={isExpanded}
isCached={isCached}
cachedDttm={cachedDttm}
removeSlice={removeSlice}
updateSliceName={updateSliceName}
toggleExpandSlice={toggleExpandSlice}
forceRefresh={forceRefresh}
editMode={this.props.editMode}
annotationQuery={annotationQuery}
/>
</div>
{
/* This usage of dangerouslySetInnerHTML is safe since it is being used to render
markdown that is sanitized with bleach. See:
https://github.com/apache/incubator-superset/pull/4390
and
https://github.com/apache/incubator-superset/commit/b6fcc22d5a2cb7a5e92599ed5795a0169385a825 */}
<div
className="slice_description bs-callout bs-callout-default"
style={isExpanded ? {} : { display: 'none' }}
ref={this.getDescriptionId(slice)}
dangerouslySetInnerHTML={{ __html: slice.description_markeddown }}
/>
<div className="row chart-container">
<input type="hidden" value="false" />
<ChartContainer
containerId={`slice-container-${slice.slice_id}`}
chartKey={chartKey}
datasource={datasource}
formData={formData}
height={this.height(slice)}
width={this.width()}
timeout={timeout}
vizType={slice.formData.viz_type}
addFilter={this.addFilter}
getFilters={this.getFilters}
clearFilter={this.clearFilter}
removeFilter={this.removeFilter}
/>
</div>
</div>
);
}
}
GridCell.propTypes = propTypes;
GridCell.defaultProps = defaultProps;
export default GridCell;