Mapbox-gl-js: CSP directives prevents map from loading

Created on 28 Jan 2017  Â·  13Comments  Â·  Source: mapbox/mapbox-gl-js

Adding the CSP directive in the meta tag as described in https://github.com/mapbox/mapbox-gl-js/blob/master/INSTALL.md#using-mapbox-with-csp does not work as expected and leads to the map not loading correctly.

Minimal example https://mapbox-csp-bug.myshopify.com/pages/mapbox-csp-bug

The map displays correctly in Chrome, but fails to load with an error on Safari (Version 10.0.2 (12602.3.12.0.1).

This precludes usage of map box gl on any shopify hosted website (and other hosts where the developer for whatever reason cannot or does not want to change the CSP header).

Original issue:
https://github.com/mapbox/mapbox-gl-js/issues/3982#issuecomment-275819486

Most helpful comment

Was running into this and fixed it by adding the following CSP directive to my server:

worker-src 'self' blob:;

All 13 comments

Here's what I see in the console when loading the codepen in Safari:

[Error] Refused to load http://production-assets.codepen.io/assets/common/stopExecutionOnTimeout-58d22c749295bca52f487966e382a94a495ac103faca9206cbd160bdf8aedf2a.js because it does not appear in the script-src directive of the Content Security Policy.
[Error] Refused to load http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js because it does not appear in the script-src directive of the Content Security Policy.
[Error] Refused to execute a script because its hash, its nonce, or 'unsafe-inline' does not appear in the script-src directive of the Content Security Policy. (index.html, line 23)

So the security policy is preventing codepen from working at all. Can you set up an example that doesn't depend on codepen?

Your example also won't work due to the inline script, and the fact that it's missing child-src blob:. The following works in Safari for me:

<meta http-equiv="Content-Security-Policy" content="default-src 'self' https://* blob: data:; script-src https://* 'sha256-NwPGqa9Mxa7ZIeBSPi4K97Vtt3uBWjwtJsUlZfeqG5E' 'unsafe-eval'; style-src 'unsafe-inline' https://*; child-src blob: ; connect-src https://*;">
<link rel="stylesheet" href="https://api.tiles.mapbox.com/mapbox-gl-js/v0.8.1/mapbox-gl.css">
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v0.8.1/mapbox-gl.js"></script>
<style>
    * {
        box-sizing: border-box;
    }
    body {
        margin: 0;
        padding: 0;
    }

    #map {
        position: absolute;
        top: 0;
        bottom: 0;
        width: 100%;
    }
</style>
<div id='map'></div>
<script>
    mapboxgl.accessToken = 'pk.eyJ1IjoiZmFsbGVuYXJ0aXN0IiwiYSI6IkRHY2JKRWMifQ.m6rylJF-IEcmwtiRsVO1WA';

    var center = [51.5, -0.1];

    var map = new mapboxgl.Map({
        container: 'map',
        center: center,
        zoom: 8,
        style: 'https://www.mapbox.com/mapbox-gl-styles/styles/mapbox-streets-v7.json'
    });
</script>

Hi @jfirebaugh Thanks for your snippet and sorry for my late night coding mistake with the code pen sample. I have setup a dev store on shopify that includes a minimal html page including the meta tag above:
https://mapbox-csp-bug.myshopify.com/pages/mapbox-csp-bug

In the process I also found why it does not work on shopify but appears to do fine on a vanilla server. The reason is that web workers do not follow the CSP of the document, but rather of the request that served it:

Workers are considered to have their own execution context, distinct from the document that created them. For this reasons they are, in general, not governed by the content security policy of the document (or parent worker) that created them. [...]
To specify a content security policy for the worker, set a Content-Security-Policy response header for the request which delivered the worker script itself.
https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#Content_security_policy

The mapbox js sdk is served without this header. My assumption is that Safari then falls back to the document's request header which ignores any changes to the meta tag for the workers.

To reproduce locally setup a server and set the following headers (as used by shopify):

add_header Content-Security-Policy "default-src 'self' https://*; connect-src 'self' https://* wss://*; font-src 'self' https://* blob: data:; frame-src 'self' https://* blob: data:; img-src 'self' https://* blob: data:; media-src 'self' https://* blob: data:; object-src 'self' https://* blob: data:; script-src 'self' https://* 'unsafe-inline' 'unsafe-eval'; style-src 'self' https://* 'unsafe-inline';";

I do not believe that this issue is limited to Shopify and would assume that other users experience similar issues. Nevertheless I also brought this up at Shopify: https://ecommerce.shopify.com/c/shopify-apis-and-technology/t/content-security-policy-response-headers-401287

The source for the worker script isn't https://api.tiles.mapbox.com/mapbox-gl-js/v0.8.1/mapbox-gl.js, it's a blob: URL that is generated at runtime. According to https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy#CSP_in_workers:

The exception to this is if the worker script's origin is a globally unique identifier (for example, if its URL has a scheme of data or blob). In this case, the worker does inherit the content security policy of the document or worker than created it.

Therefore the worker script should be allowed in this scenario, since both the meta tag and the response header include child-src blob:. It looks like a Safari bug to me.

Actually, it looks like a Shopify bug. They appear to be returning different CSP headers depending on the browser.

Chrome -- child-src present:

Content-Security-Policy: default-src 'self' https://*; child-src 'self' https://* blob: data:; connect-src 'self' https://* wss://*; font-src 'self' https://* blob: data:; img-src 'self' https://* blob: data:; media-src 'self' https://* blob: data:; object-src 'self' https://* blob: data:; script-src 'self' https://* 'unsafe-inline' 'unsafe-eval'; style-src 'self' https://* 'unsafe-inline'; report-uri /csp-report?source%5Baction%5D=pages&source%5Bapp%5D=Shopify&source%5Bcontroller%5D=storefront_section%2Fshop&source%5Bsection%5D=storefront&source%5Buuid%5D=7cbe81cf-46cc-4028-b139-210f67ccff28

Safari -- child-src missing:

Content-Security-Policy: default-src 'self' https://*; connect-src 'self' https://* wss://*; font-src 'self' https://* blob: data:; frame-src 'self' https://* blob: data:; img-src 'self' https://* blob: data:; media-src 'self' https://* blob: data:; object-src 'self' https://* blob: data:; script-src 'self' https://* 'unsafe-inline' 'unsafe-eval'; style-src 'self' https://* 'unsafe-inline'; report-uri /csp-report?source%5Baction%5D=pages&source%5Bapp%5D=Shopify&source%5Bcontroller%5D=storefront_section%2Fshop&source%5Bsection%5D=storefront&source%5Buuid%5D=5b1533f9-bdf6-4cd8-8329-cca8ed0b222a

Closing since this is an issue with Shopify's browser sniffing.

Running into the same issue on Shopify. Can't find a solution for this

Was running into this and fixed it by adding the following CSP directive to my server:

worker-src 'self' blob:;

it is most strange. child-src blob:; works for cordova ios, but not worker-src blob:;

@jonnybarnes Does this also affect iframes? I'm embedding via iframe as shown here but i keep getting:

Content Security Policy: Directive ‘child-src’ has been deprecated. Please use directive ‘worker-src’ to control workers, or directive ‘frame-src’ to control frames respectively.

Thanks

Was this page helpful?
0 / 5 - 0 ratings

Related issues

stevage picture stevage  Â·  3Comments

foundryspatial-duncan picture foundryspatial-duncan  Â·  3Comments

aderaaij picture aderaaij  Â·  3Comments

BernhardRode picture BernhardRode  Â·  3Comments

rigoneri picture rigoneri  Â·  3Comments