Spaces:
Paused
Paused
Download docs/admin_docs_versioned_docs/version-6.1.0/security/security.mdx from Leon4gr45/powerbi: direct link, hf CLI and curl.
- Browser
- Download file 32 kB
-
https://huggingface.co/spaces/Leon4gr45/powerbi/resolve/main/docs/admin_docs_versioned_docs/version-6.1.0/security/security.mdx
- Command line
-
hf download hf://spaces/Leon4gr45/powerbi/docs/admin_docs_versioned_docs/version-6.1.0/security/security.mdx
-
curl -L -o security.mdx https://huggingface.co/spaces/Leon4gr45/powerbi/resolve/main/docs/admin_docs_versioned_docs/version-6.1.0/security/security.mdx
32 kB
| --- | |
| title: Security Configurations | |
| sidebar_position: 1 | |
| --- | |
| Authentication and authorization in Superset is handled by Flask AppBuilder (FAB), an application development framework | |
| built on top of Flask. FAB provides authentication, user management, permissions and roles. | |
| Please read its [Security documentation](https://flask-appbuilder.readthedocs.io/en/latest/security.html). | |
| ### Provided Roles | |
| Superset ships with a set of roles that are handled by Superset itself. You can assume | |
| that these roles will stay up-to-date as Superset evolves (and as you update Superset versions). | |
| Even though **Admin** users have the ability, we don't recommend altering the | |
| permissions associated with each role (e.g. by removing or adding permissions to them). The permissions | |
| associated with each role will be re-synchronized to their original values when you run | |
| the **superset init** command (often done between Superset versions). | |
| A table with the permissions for these roles can be found at [/RESOURCES/STANDARD_ROLES.md](https://github.com/apache/superset/blob/master/RESOURCES/STANDARD_ROLES.md). | |
| ### Admin | |
| Admins have all possible rights, including granting or revoking rights from other | |
| users and altering other peopleβs slices and dashboards. | |
| > #### Threat Model and Privilege Boundaries: The Admin Role | |
| > | |
| > Apache Superset is built with a granular permission model where users assigned the Admin role are considered fully trusted. Admins possess complete control over the application's configuration, UI rendering, and access controls. | |
| > | |
| > Consequently, actions performed by an Admin that alter the application's behavior or presentationβsuch as injecting custom CSS, modifying Jinja templates, or altering security flagsβare intended administrative capabilities by design. | |
| > | |
| > In accordance with MITRE CNA Rule 4.1, a vulnerability must represent a violation of an explicit security policy. Because the Admin role is defined as a trusted operational boundary, actions executed with Admin privileges do not cross a security perimeter. Therefore, exploit vectors that strictly require Admin access are not classified as security vulnerabilities and are ineligible for CVE assignment. | |
| ### Alpha | |
| Alpha users have access to all data sources, but they cannot grant or revoke access | |
| from other users. They are also limited to altering the objects that they own. Alpha users can add and alter data sources. | |
| ### Gamma | |
| Gamma users have limited access. They can only consume data coming from data sources | |
| they have been given access to through another complementary role. They only have access to | |
| view the slices and dashboards made from data sources that they have access to. Currently Gamma | |
| users are not able to alter or add data sources. We assume that they are mostly content consumers, though they can create slices and dashboards. | |
| Also note that when Gamma users look at the dashboards and slices list view, they will | |
| only see the objects that they have access to. | |
| ### sql_lab | |
| The **sql_lab** role grants access to SQL Lab. Note that while **Admin** users have access | |
| to all databases by default, both **Alpha** and **Gamma** users need to be given access on a per database basis. | |
| Beyond the base `sql_lab` role, two additional SQL Lab permissions must be explicitly granted for users who need these capabilities: | |
| | Permission | Feature | | |
| | ------------------------------------- | --------------------------------------- | | |
| | `can_estimate_query_cost` on `SQLLab` | Estimate query cost before running | | |
| | `can_format_sql` on `SQLLab` | Format SQL using the database's dialect | | |
| Grant these in **Security β List Roles** by adding the permissions to the relevant role. | |
| ### Public | |
| The **Public** role is the most restrictive built-in role, designed specifically for anonymous/unauthenticated | |
| users who need to view dashboards. It provides minimal read-only access for: | |
| - Viewing dashboards and charts | |
| - Using interactive dashboard filters | |
| - Accessing dashboard and chart permalinks | |
| - Reading embedded dashboards | |
| - Viewing annotations on charts | |
| The Public role explicitly excludes: | |
| - Any write permissions on dashboards, charts, or datasets | |
| - SQL Lab access | |
| - Share functionality | |
| - User profile or admin features | |
| - Menu access to most Superset features | |
| Anonymous users are automatically assigned the Public role when `AUTH_ROLE_PUBLIC` is configured | |
| (a Flask-AppBuilder setting). The `PUBLIC_ROLE_LIKE` setting is **optional** and controls what | |
| permissions are synced to the Public role when you run `superset init`: | |
| ```python | |
| # Optional: Sync sensible default permissions to the Public role | |
| PUBLIC_ROLE_LIKE = "Public" | |
| # Alternative: Copy permissions from Gamma for broader access | |
| # PUBLIC_ROLE_LIKE = "Gamma" | |
| ``` | |
| If you prefer to manually configure the Public role's permissions (or use `DASHBOARD_RBAC` to | |
| grant access at the dashboard level), you do not need to set `PUBLIC_ROLE_LIKE`. | |
| **Important notes:** | |
| - **Data access is still required:** The Public role only grants UI/API permissions. You must | |
| also grant access to specific datasets necessary to view a dashboard. As with other roles, | |
| this can be done in two ways: | |
| - **Without `DASHBOARD_RBAC`:** Dashboards only appear in the list and are accessible if | |
| the user has permission to at least one of their datasets. Grant dataset access by editing | |
| the Public role in the Superset UI (Menu β Security β List Roles β Public) and adding the | |
| relevant data sources. All published dashboards using those datasets become visible. | |
| - **With `DASHBOARD_RBAC` enabled:** Anonymous users will only see dashboards where the | |
| "Public" role has been explicitly added in the dashboard's properties. Dataset permissions | |
| are not requiredβDASHBOARD_RBAC handles the cascading permissions check. This provides | |
| fine-grained control over which dashboards are publicly visible. | |
| - **Role synchronization:** Built-in role permissions (Admin, Alpha, Gamma, sql_lab, and Public | |
| when `PUBLIC_ROLE_LIKE = "Public"`) are synchronized when you run `superset init`. Any manual | |
| permission edits to these roles may be overwritten during upgrades. To customize the Public | |
| role permissions, you can either: | |
| - Edit the Public role directly and avoid setting `PUBLIC_ROLE_LIKE` (permissions won't be | |
| overwritten by `superset init`) | |
| - Copy the Public role via "Copy Role" in the Superset web UI, save it under a different name | |
| (e.g., "Public_Custom"), customize the permissions, then update **both** configs: | |
| `PUBLIC_ROLE_LIKE = "Public_Custom"` and `AUTH_ROLE_PUBLIC = "Public_Custom"` | |
| ### Managing Data Source Access for Gamma Roles | |
| Hereβs how to provide users access to only specific datasets. First make sure the users with | |
| limited access have [only] the Gamma role assigned to them. Second, create a new role (Menu -> Security -> List Roles) and click the + sign. | |
| This new window allows you to give this new role a name, attribute it to users and select the | |
| tables in the **Permissions** dropdown. To select the data sources you want to associate with this role, simply click on the dropdown and use the typeahead to search for your table names. | |
| You can then confirm with users assigned to the **Gamma** role that they see the | |
| objects (dashboards and slices) associated with the tables you just extended them. | |
| ### Dashboard Access Control | |
| Access to dashboards is managed via owners (users that have edit permissions to the dashboard). | |
| Non-owner user access can be managed in two ways. Note that dashboards must be published to be | |
| visible to other users. | |
| #### Dataset-Based Access (Default) | |
| By default, users can view published dashboards if they have access to at least one dataset | |
| used in that dashboard. Grant dataset access by adding the relevant data source permissions | |
| to a role (Menu β Security β List Roles). | |
| This is the simplest approach but provides all-or-nothing access based on dataset permissionsβ | |
| if a user has access to a dataset, they can see all published dashboards using that dataset. | |
| #### Dashboard-Level Access (DASHBOARD_RBAC) | |
| For fine-grained control over which dashboards specific roles can access, enable the | |
| `DASHBOARD_RBAC` feature flag: | |
| ```python | |
| FEATURE_FLAGS = { | |
| "DASHBOARD_RBAC": True, | |
| } | |
| ``` | |
| With this enabled, you can assign specific roles to each dashboard in its properties. Users | |
| will only see dashboards where their role is explicitly added. | |
| **Important considerations:** | |
| - Dashboard access **bypasses** dataset-level checksβgranting a role access to a dashboard | |
| implicitly grants read access to all charts and datasets in that dashboard | |
| - Dashboards without any assigned roles fall back to dataset-based access | |
| - The dashboard must still be published to be visible | |
| This feature is particularly useful for: | |
| - Making specific dashboards public while keeping others private | |
| - Granting access to dashboards without exposing the underlying datasets for other uses | |
| - Creating dashboard-specific access patterns that don't align with dataset ownership | |
| ### SQL Execution Security Considerations | |
| Apache Superset includes features designed to provide safeguards when interacting with connected databases, such as the `DISALLOWED_SQL_FUNCTIONS` configuration setting. This aims to prevent the execution of potentially harmful database functions or system variables directly from Superset interfaces like SQL Lab. | |
| However, it is crucial to understand the following: | |
| **Superset is Not a Database Firewall**: Superset's built-in checks, like `DISALLOWED_SQL_FUNCTIONS`, provide a layer of protection but cannot guarantee complete security against all database-level threats or advanced bypass techniques (like specific comment injection methods). They should be viewed as a supplement to, not a replacement for, robust database security. | |
| **Configuration is Key**: The effectiveness of Superset's safeguards heavily depends on proper configuration by the Superset administrator. This includes maintaining the `DISALLOWED_SQL_FUNCTIONS` list, carefully managing feature flags (like `ENABLE_TEMPLATE_PROCESSING`), and configuring other security settings appropriately. | |
| **Database Security is Paramount**: The ultimate responsibility for securing database access, controlling permissions, and preventing unauthorized function execution lies with the database administrators (DBAs) and security teams managing the underlying database instance. | |
| **Recommended Database Practices**: We strongly recommend implementing security best practices at the database level, including: | |
| - **Least Privilege**: Connecting Superset using dedicated database user accounts with the minimum permissions required for Superset's operation (typically read-only access to necessary schemas/tables). | |
| - **Database Roles & Permissions**: Utilizing database-native roles and permissions to restrict access to sensitive functions, system variables (like `@@hostname`), schemas, or tables. | |
| - **Network Security**: Employing network-level controls like database firewalls or proxies to restrict connections. | |
| - **Auditing**: Enabling database-level auditing to monitor executed queries and access patterns. | |
| By combining Superset's configurable safeguards with strong database-level security practices, you can achieve a more robust and layered security posture. | |
| **Dataset Sample Access**: The `get_samples()` endpoint now enforces datasource-level access control. Users can only fetch sample rows from datasets they have been explicitly granted access to β the same permission check applied when running chart queries. This closes a prior gap where unauthenticated or under-privileged access could retrieve sample data. | |
| ### REST API for user & role management | |
| Flask-AppBuilder supports a REST API for user CRUD, | |
| but this feature is in beta and is not enabled by default in Superset. | |
| To enable this feature, set the following in your Superset configuration: | |
| ```python | |
| FAB_ADD_SECURITY_API = True | |
| ``` | |
| Once configured, the documentation for additional "Security" endpoints will be visible in Swagger for you to explore. | |
| ### API Key Authentication | |
| Superset supports long-lived API keys for service accounts, CI/CD pipelines, and programmatic integrations (including MCP clients). | |
| #### Enabling API Key Authentication | |
| API key authentication is **disabled by default**. To turn it on, set the Flask-AppBuilder config value in `superset_config.py` and also enable the matching feature flag so the management UI is exposed: | |
| ```python | |
| FAB_API_KEY_ENABLED = True | |
| FEATURE_FLAGS = { | |
| "FAB_API_KEY_ENABLED": True, | |
| } | |
| ``` | |
| The config value registers the `ApiKeyApi` blueprint on the backend; the feature flag controls whether the UI for managing keys appears for the user. See the [Feature Flags](/admin-docs/configuration/feature-flags) documentation for more on feature flag configuration. | |
| #### Creating an API Key | |
| Once enabled, each user manages their own keys from their profile page: | |
| 1. Open the user menu (top-right) and click **Info** to navigate to the User Info page | |
| 2. Expand the **API Keys** section | |
| 3. Click **+ API Key** | |
| 4. Enter a name and (optionally) an expiration date | |
| 5. Copy the generated token β it is shown only once | |
| Only users with the `can_read` and `can_write` permissions on `ApiKey` (granted by default to Admins) can manage API keys. | |
| #### Using an API Key | |
| Pass the key as a Bearer token in the `Authorization` header: | |
| ``` | |
| Authorization: Bearer <your-api-key> | |
| ``` | |
| This works for all REST API endpoints and the MCP server. The request is executed with the permissions of the user who created the key. | |
| #### Use Cases | |
| - **CI/CD pipelines** β automated chart/dashboard exports and imports | |
| - **MCP integrations** β connect AI assistants without interactive login | |
| - **External services** β dashboards embedded in other applications | |
| - **Service accounts** β long-lived credentials that don't expire with session cookies | |
| :::caution | |
| Store API keys securely. Anyone with a valid key can make requests on behalf of the creating user. Revoke keys promptly if they are compromised by deleting them from the **API Keys** section of your User Info page. | |
| ::: | |
| ### Customizing Permissions | |
| The permissions exposed by FAB are very granular and allow for a great level of | |
| customization. FAB creates many permissions automatically for each model that is | |
| created (can_add, can_delete, can_show, can_edit, β¦) as well as for each view. | |
| On top of that, Superset can expose more granular permissions like **all_datasource_access**. | |
| **We do not recommend altering the 3 base roles as there are a set of assumptions that | |
| Superset is built upon**. It is possible though for you to create your own roles, and union them to existing ones. | |
| ### Permissions | |
| Roles are composed of a set of permissions, and Superset has many categories of | |
| permissions. Here are the different categories of permissions: | |
| - Model & Action: models are entities like Dashboard, Slice, or User. Each model has | |
| a fixed set of permissions, like **can_edit**, **can_show**, **can_delete**, **can_list**, **can_add**, | |
| and so on. For example, you can allow a user to delete dashboards by adding **can_delete** on | |
| Dashboard entity to a role and granting this user that role. | |
| - Views: views are individual web pages, like the Explore view or the SQL Lab view. | |
| When granted to a user, they will see that view in its menu items, and be able to load that page. | |
| - Data source: For each data source, a permission is created. If the user does not have the | |
| `all_datasource_access permission` granted, the user will only be able to see Slices or explore the data sources that are granted to them | |
| - Database: Granting access to a database allows for the user to access all | |
| data sources within that database, and will enable the user to query that | |
| database in SQL Lab, provided that the SQL Lab specific permission have been granted to the user | |
| ### Restricting Access to a Subset of Data Sources | |
| We recommend giving a user the **Gamma** role plus any other roles that would add | |
| access to specific data sources. We recommend that you create individual roles for | |
| each access profile. For example, the users on the Finance team might have access to a set of | |
| databases and data sources; these permissions can be consolidated in a single role. | |
| Users with this profile then need to be assigned the **Gamma** role as a foundation to | |
| the models and views they can access, and that Finance role that is a collection of permissions to data objects. | |
| A user can have multiple roles associated with them. For example, an executive on the Finance | |
| team could be granted **Gamma**, **Finance**, and the **Executive** roles. The **Executive** | |
| role could provide access to a set of data sources and dashboards made available only to executives. | |
| In the **Dashboards** view, a user can only see the ones they have access to | |
| based on the roles and permissions that were attributed. | |
| ### Row Level Security | |
| Using Row Level Security filters (under the **Security** menu) you can create filters | |
| that are assigned to a particular dataset, as well as a set of roles. | |
| If you want members of the Finance team to only have access to | |
| rows where `department = "finance"`, you could: | |
| - Create a Row Level Security filter with that clause (`department = "finance"`) | |
| - Then assign the clause to the **Finance** role and the dataset it applies to | |
| The **clause** field, which can contain arbitrary text, is then added to the generated | |
| SQL statement's WHERE clause. So you could even do something like create a filter | |
| for the last 30 days and apply it to a specific role, with a clause | |
| like `date_field > DATE_SUB(NOW(), INTERVAL 30 DAY)`. It can also support | |
| multiple conditions: `client_id = 6` AND `advertiser="foo"`, etc. | |
| RLS clauses also support **Jinja templating** when `ENABLE_TEMPLATE_PROCESSING` is enabled, so you can write dynamic filters such as | |
| `user_id = '{{ current_username() }}'` to restrict rows based on the logged-in user. | |
| #### Filter Types | |
| There are two types of RLS filters: | |
| - **Regular** β The filter clause is applied when the querying user belongs to one of the | |
| roles assigned to the filter. Use this to restrict what specific roles can see. | |
| - **Base** β The filter clause is applied to **all** users _except_ those in the assigned | |
| roles. Use this to define a default restriction that privileged roles (e.g. Admin) are | |
| exempt from. For example, a Base filter with clause `1 = 0` and the Admin role would | |
| hide all rows from everyone except Admin β useful as a deny-by-default baseline. | |
| #### Group Keys and Filter Combination | |
| All applicable RLS filters are combined before being added to the query. The combination | |
| rules are: | |
| - Filters that share the **same group key** are combined with **OR** (any match within | |
| the group is sufficient). | |
| - Different filter groups (different group keys, or no group key) are combined with | |
| **AND** (all groups must match). | |
| - Filters with **no group key** are each treated as their own group and are always AND'd. | |
| For example, if a dataset has three filters: | |
| | Filter | Clause | Group Key | | |
| | ------ | -------------------------- | ------------ | | |
| | F1 | `department = 'Finance'` | `department` | | |
| | F2 | `department = 'Marketing'` | `department` | | |
| | F3 | `region = 'Europe'` | `region` | | |
| The resulting WHERE clause would be: | |
| ```sql | |
| (department = 'Finance' OR department = 'Marketing') AND (region = 'Europe') | |
| ``` | |
| :::caution Conflicting filters | |
| It is possible to create filters that conflict and produce an empty result set. For | |
| example, the filters `client_id = 4` and `client_id = 5` **without a shared group key** | |
| will be AND'd together, producing `client_id = 4 AND client_id = 5`, which can never | |
| be true. | |
| If you intend for these to be alternatives, assign them the **same group key** so they | |
| are OR'd instead. | |
| ::: | |
| #### RLS and Virtual (SQL-Based) Datasets | |
| RLS filters are assigned to **datasets**, not to underlying database tables directly. This | |
| has important implications when working with virtual (SQL-based) datasets: | |
| - **Physical datasets** (backed directly by a table or view) β RLS filters assigned to | |
| the dataset are added as WHERE clauses to the query. | |
| - **Virtual datasets** (defined by a custom SQL query) β RLS filters assigned directly to | |
| the virtual dataset are applied to the _outer_ query that wraps the dataset's SQL. | |
| Additionally, RLS filters on the **underlying physical datasets** referenced by the | |
| virtual dataset's SQL are injected into the inner subquery for each referenced table. | |
| For example, if you have: | |
| 1. A physical dataset `orders` with RLS filter `region = 'US'` | |
| 2. A virtual dataset defined as `SELECT * FROM orders WHERE status = 'active'` | |
| A user affected by the RLS filter will effectively see: | |
| ```sql | |
| SELECT * FROM ( | |
| SELECT * FROM orders WHERE (region = 'US') AND status = 'active' | |
| ) ... | |
| ``` | |
| **Key considerations for virtual datasets:** | |
| - You generally do **not** need to duplicate RLS filters on both the physical and virtual | |
| dataset β filters on the physical dataset are applied automatically at query time. | |
| - If you assign an RLS filter directly to a virtual dataset, the clause must reference | |
| columns available in the virtual dataset's _output_, not necessarily the underlying | |
| table's columns. | |
| - In **SQL Lab**, RLS is enforced only when the `RLS_IN_SQLLAB` feature flag is enabled: | |
| queries run against tables that have associated datasets with RLS filters will then have | |
| the appropriate predicates injected automatically. | |
| #### Checking RLS Filters via the API | |
| You can use the RLS REST API to audit which filters are configured and which datasets | |
| they affect. This requires the `can_read` permission on the `Row Level Security` resource. | |
| **List all RLS rules:** | |
| ``` | |
| GET /api/v1/rowlevelsecurity/ | |
| ``` | |
| **Filter RLS rules for a specific dataset** (using [Rison](https://github.com/Nanonid/rison) query syntax): | |
| ``` | |
| GET /api/v1/rowlevelsecurity/?q=(filters:!((col:tables,opr:rel_m_m,value:<dataset_id>))) | |
| ``` | |
| **Filter RLS rules by role:** | |
| ``` | |
| GET /api/v1/rowlevelsecurity/?q=(filters:!((col:roles,opr:rel_m_m,value:<role_id>))) | |
| ``` | |
| **View details of a specific rule** (including clause, assigned datasets, and roles): | |
| ``` | |
| GET /api/v1/rowlevelsecurity/<id> | |
| ``` | |
| The response includes the filter's `name`, `filter_type` (Regular or Base), `clause`, | |
| `group_key`, assigned `tables` (with id, schema, and table_name), and assigned `roles` | |
| (with id and name). | |
| :::tip Auditing RLS for virtual datasets | |
| To find all RLS rules that could affect a particular virtual dataset, query the list | |
| endpoint filtered by that dataset's ID for any directly-assigned rules. Then also check | |
| the physical datasets referenced in the virtual dataset's SQL, since their RLS filters | |
| are applied at query time too. | |
| ::: | |
| ### User Sessions | |
| Superset uses [Flask](https://pypi.org/project/Flask/) | |
| and [Flask-Login](https://pypi.org/project/Flask-Login/) for user session management. | |
| Session cookies are used to maintain session info and user state between requests, | |
| although they do not contain personal user information they serve the purpose of identifying | |
| a user session on the server side. | |
| The session cookie is encrypted with the application `SECRET_KEY` and cannot be read by the client. | |
| So it's very important to keep the `SECRET_KEY` secret and set to a secure unique complex random value. | |
| Flask and Flask-Login offer a number of configuration options to control session behavior. | |
| - Relevant Flask settings: | |
| `SESSION_COOKIE_HTTPONLY`: (default: `False`): Controls if cookies should be set with the `HttpOnly` flag. | |
| `SESSION_COOKIE_SECURE`: (default: `False`) Browsers will only send cookies with requests over | |
| HTTPS if the cookie is marked βsecureβ. The application must be served over HTTPS for this to make sense. | |
| `SESSION_COOKIE_SAMESITE`: (default: "Lax") Prevents the browser from sending this cookie along with cross-site requests. | |
| `PERMANENT_SESSION_LIFETIME`: (default: "31 days") The lifetime of a permanent session as a `datetime.timedelta` object. | |
| #### Switching to server side sessions | |
| Server side sessions offer benefits over client side sessions on security and performance. | |
| By enabling server side sessions, the session data is stored server side and only a session ID | |
| is sent to the client. When a user logs in, a session is created server side and the session ID | |
| is sent to the client in a cookie. The client will send the session ID with each request and the | |
| server will use it to retrieve the session data. | |
| On logout, the session is destroyed server side and the session cookie is deleted on the client side. | |
| This reduces the risk for replay attacks and session hijacking. | |
| Superset uses [Flask-Session](https://flask-session.readthedocs.io/en/latest/) to manage server side sessions. | |
| To enable this extension you have to set: | |
| ```python | |
| SESSION_SERVER_SIDE = True | |
| ``` | |
| Flask-Session offers multiple backend session interfaces for Flask, here's an example for Redis: | |
| ```python | |
| from redis import Redis | |
| SESSION_TYPE = "redis" | |
| SESSION_REDIS = Redis(host="redis", port=6379, db=0) | |
| # sign the session cookie sid | |
| SESSION_USE_SIGNER = True | |
| ``` | |
| ### Content Security Policy (CSP) | |
| Superset uses the [Talisman](https://pypi.org/project/flask-talisman/) extension to enable implementation of a | |
| [Content Security Policy (CSP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP), an added | |
| layer of security that helps to detect and mitigate certain types of attacks, including | |
| Cross-Site Scripting (XSS) and data injection attacks. | |
| A CSP makes it possible for server administrators to reduce or eliminate the vectors by which XSS can | |
| occur by specifying the domains that the browser should consider to be valid sources of executable scripts. | |
| A CSP-compatible browser will then only execute scripts loaded in source files received from those allowed domains, | |
| ignoring all other scripts (including inline scripts and event-handling HTML attributes). | |
| A policy is described using a series of policy directives, each of which describes the policy for | |
| a certain resource type or policy area. You can check possible directives | |
| [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy). | |
| 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 `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. | |
| When running in production mode, Superset will check at startup for the presence | |
| of a CSP. If one is not found, it will issue a warning with the security risks. For environments | |
| where CSP policies are defined outside of Superset using other software, administrators can disable | |
| this warning using the `CONTENT_SECURITY_POLICY_WARNING` key in `config.py`. | |
| #### CSP Requirements | |
| - Superset needs the `style-src unsafe-inline` CSP directive in order to operate. | |
| ``` | |
| 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()`. | |
| ```html | |
| <script nonce="{{ csp_nonce() }}"> | |
| /* my script */ | |
| </script> | |
| ``` | |
| - Some dashboards load images using data URIs and require `data:` in their `img-src` | |
| ``` | |
| img-src 'self' data: | |
| ``` | |
| - MapBox charts use workers and need to connect to MapBox servers in addition to the Superset origin | |
| ``` | |
| worker-src 'self' blob: | |
| connect-src 'self' https://api.mapbox.com https://events.mapbox.com | |
| ``` | |
| - Cartodiagram charts request map data (image and json) from external resources that can be edited by users, | |
| and therefore either require a list of allowed domains to request from or a wildcard (`'*'`) for `img-src` and `connect-src`. | |
| - 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/) | |
| #### Other Talisman security considerations | |
| Setting `TALISMAN_ENABLED = True` will invoke Talisman's protection with its default arguments, | |
| 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 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 load 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": True, | |
| "content_security_policy": { ... | |
| ``` | |
| #### Configuring Talisman in Superset | |
| Talisman settings in Superset can be modified using superset_config.py. If you need to adjust security policies, you can override the default configuration. | |
| Example: Overriding Talisman Configuration in superset_config.py for loading images form s3 or other external sources. | |
| ```python | |
| TALISMAN_CONFIG = { | |
| "content_security_policy": { | |
| "base-uri": ["'self'"], | |
| "default-src": ["'self'"], | |
| "img-src": [ | |
| "'self'", | |
| "blob:", | |
| "data:", | |
| "https://apachesuperset.gateway.scarf.sh", | |
| "https://static.scarf.sh/", | |
| # "https://cdn.brandfolder.io", # Uncomment when SLACK_ENABLE_AVATARS is True # noqa: E501 | |
| "ows.terrestris.de", | |
| "aws.s3.com", # Add Your Bucket or external data source | |
| ], | |
| "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, | |
| "session_cookie_secure": False, | |
| } | |
| ``` | |
| For more information on setting up Talisman, please refer to | |
| https://superset.apache.org/admin-docs/configuration/networking-settings/#changing-flask-talisman-csp. | |
| ### Reporting Security Vulnerabilities | |
| Apache Software Foundation takes a rigorous standpoint in annihilating the security issues in its | |
| software projects. Apache Superset is highly sensitive and forthcoming to issues pertaining to its | |
| features and functionality. | |
| If you have apprehensions regarding Superset security or you discover vulnerability or potential | |
| threat, donβt hesitate to get in touch with the Apache Security Team by dropping a mail at | |
| security@apache.org. In the mail, specify the project name Superset with the description of the | |
| issue or potential threat. You are also urged to recommend the way to reproduce and replicate the | |
| issue. The security team and the Superset community will get back to you after assessing and | |
| analysing the findings. | |
| PLEASE PAY ATTENTION to report the security issue on the security email before disclosing it on | |
| public domain. The ASF Security Team maintains a page with the description of how vulnerabilities | |
| and potential threats are handled, check [their web page](https://apache.org/security/committers.html) | |
| for more details. | |