superset icon indicating copy to clipboard operation
superset copied to clipboard

Cannot send Cross-Origin-Resource-Policy from embed code

Open loretoparisi opened this issue 11 months ago • 3 comments

Bug description

I cannot force the embedded chart to sent the Cross-Origin-Resource-Policy header. I have set the CORS options and embedding parameters for iframe embedding as well as Cookie and CSP policy. Superset is hosted at localhost:8088 while I'm embedding charts at localhost:9000. I have followed the configuraiton of Flask CORS_OPTIONS here, but I cannot get rid of sending the right headers from the embedded chart.

This is my superset_config.py

# CORS OPTIONS
ENABLE_CORS = True
CORS_OPTIONS = { 
    'supports_credentials': True, 
    'allow_headers': ['*'], 
    'resources':['*'], 
    'origins': [ 'http://localhost:9000', 'http://localhost:8088']
}
SUPERSET_FEATURE_EMBEDDED_SUPERSET=True

# EMBED CODE  IFRAME OPTIONS
OVERRIDE_HTTP_HEADERS = {'X-Frame-Options': 'ALLOWALL'}
HTTP_HEADERS = {"X-Frame-Options":"ALLOWALL"}

SUPERSET_WEBSERVER_DOMAINS = [ 'localhost', 'localhost:8088', 'localhost:9000']
# SESSION_COOKIE_DOMAIN

#  (default: "Lax") Prevents the browser from sending this cookie along with cross-site requests.
SESSION_COOKIE_SAMESITE = "None"

#  (default: False): Controls if cookies should be set with the HttpOnly flag.
SESSION_COOKIE_HTTPONLY = False

#  (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_SECURE = False

#CSRF_COOKIE_HTTPONLY = False
WTF_CSRF_ENABLED = False

# TALISMAN_ENABLED defaults to True; set this to False in order to disable CSP
# @see https://superset.apache.org/docs/security/#csp-requirements
TALISMAN_ENABLED = False

# you grant public role the same set of permissions as for the GAMMA role. 
# This is useful if one wants to enable anonymous users to view dashboards.
# @see https://apache-superset.readthedocs.io/en/0.35.1/security.html
PUBLIC_ROLE_LIKE_GAMMA = False

# For environments where CSP policies are defined outside of Superset using other software, administrators can disable this warning 
CONTENT_SECURITY_POLICY_WARNING = False

and the iframe was

<iframe
  width="600"
  height="400"
  seamless
  frameBorder="0"
  allowfullscreen
  scrolling="no"
  src="http://localhost:8088/superset/explore/p/a8yN1wGMobp/?standalone=1&height=400&show_filters=true&expand_filters=true"
>
</iframe>

while the python server serving that iframe is

#!/usr/bin/env python3
from http.server import HTTPServer, SimpleHTTPRequestHandler, test
import sys

class CORSRequestHandler (SimpleHTTPRequestHandler):
    def end_headers (self):
        """
            Cross-Origin-Resource-Policy: cross-origin if the resource is served from another location than your website. ⚠️If you set this header, any website can embed this resource.
            Cross-Origin-Resource-Policy: same-site if the resource and your site are served from the same site.
            Cross-Origin-Embedder-Policy: credentialless instead of require-corp. It allows loading the resource, despite the missing CORP header, at the cost of requesting it without credentials like Cookies.
        """
        
        self.send_header('Cross-Origin-Embedder-Policy', 'credentialless') #require-corp
        self.send_header('Cross-Origin-Opener-Policy', 'cross-origin') #same-origin
        self.send_header('Cross-Origin-Resource-Policy', ' cross-origin')
        self.send_header('X-Frame-Options', 'allow-from *')
        self.send_header("Access-Control-Allow-Origin", "*")

        SimpleHTTPRequestHandler.end_headers(self)

test(CORSRequestHandler, HTTPServer, port=int(sys.argv[1]) if len(sys.argv) > 1 else 8000)

How to reproduce the bug

  1. Copy the superset_config.py provided above
  2. Copy the html code above in a embed.html page
  3. Create a cors.py python code
  4. execute python cors.py 9000 to serve the embedded chart

Screenshots/recordings

The Chrome error was

Specify a Cross-Origin Resource Policy to prevent a resource from being blocked
Because your site has the Cross-Origin Embedder Policy (COEP) enabled, each resource must specify a suitable Cross-Origin Resource Policy (CORP). This behavior prevents a document from loading cross-origin resources which don’t explicitly grant permission to be loaded.

To solve this, add the following to the resource’ response header:

Cross-Origin-Resource-Policy: same-site if the resource and your site are served from the same site.
Cross-Origin-Resource-Policy: cross-origin if the resource is served from another location than your website. ⚠️If you set this header, any website can embed this resource.

Alternatively, the document can use the variant: Cross-Origin-Embedder-Policy: credentialless instead of require-corp. It allows loading the resource, despite the missing CORP header, at the cost of requesting it without credentials like Cookies.

Superset version

master / latest-dev

Python version

3.9

Node version

18 or greater

Browser

Chrome

Additional context

No response

Checklist

  • [X] I have searched Superset docs and Slack and didn't find a solution to my problem.
  • [X] I have searched the GitHub issue tracker and didn't find a similar bug report.
  • [X] I have checked Superset's logs for errors and if I found a relevant Python stacktrace, I included it here as text in the "additional context" section.

loretoparisi avatar Mar 04 '24 11:03 loretoparisi

[NOTE]

Using

OVERRIDE_HTTP_HEADERS = { 'X-Frame-Options': 'ALLOWALL' }
HTTP_HEADERS = { "X-Frame-Options" : "ALLOWALL" }

or as detailed here

HTTP_HEADERS = {}

does not solve this issue.

loretoparisi avatar Mar 04 '24 11:03 loretoparisi

My solution was to write a Flask Middlware to send the proper headers, specifically

response.headers.add("Cross-Origin-Embedder-Policy", 'require-corp')
response.headers.add("Cross-Origin-Resource-Policy", 'cross-origin')

As alternative, when using a reverse proxy (e.g. nginix) it is possible to add to the nginix/nginix.conf

add_header Cross-Origin-Resource-Policy "cross-origin";

Of course the Flask middleware solution is more flexible for development purposes.

loretoparisi avatar Mar 07 '24 17:03 loretoparisi

This will only work if you disable Talisman and set your own Content Security Policy in the superset_config.py #Disables the CSP **TALISMAN_ENABLED = False

#Allows any website to embed the iframe on its website #OVERRIDE_HTTP_HEADERS = { "X-Frame-Options": "ALLOWALL" }

#Allows only your website to be the only website allowed to embed dashboards OVERRIDE_HTTP_HEADERS = { "Content-Security-Policy": "frame-ancestors http://your.domain.com;" }

ALLOW-FROM http://your.domain.com is deprecated and no longer works on modern browsers.

@loretoparisi**

WaudoDavid avatar Apr 23 '24 10:04 WaudoDavid