1

I added a fetch call in my entry.js file:

fetch('https://ipinfo.io/json')
  .then(response => response.json())
  .then(data => console.log(data));

My webpack build was fine until I added that, then i started getting errors regarding Content Security Policy.

Previously, I didn't have any content security policy defined.

I've tried several approaches to resolve errors (see end of post), the latest was adding this to head section of index.html file:

<meta http-equiv="Content-Security-Policy" content="script-src 'self'; connect-src https://ipinfo.io/json">

Now I am getting these errors in Chrome developer tools console, which seem to contradict themselves:

Error #1 - relating to jquery ajax get request to my own api

bundle.js:25 Refused to connect to 'http://localhost:3000/api/v1/resource?parameter=false&_=1598715905517' because it violates the following Content Security Policy directive: "connect-src https://ipinfo.io/json".

Error #2 - relating to fetch call to external website

bundle.js:1 Refused to connect to 'https://ipinfo.io/json' because it violates the following Content Security Policy directive: "default-src 'self'". Note that 'connect-src' was not explicitly set, so 'default-src' is used as a fallback.

Note: This second error says that connect-src is not explicitly set, however the first error occurs because it is explicitly set.

Error #3 - relating to fetch call to external website

bundle.js:1 Refused to connect to 'https://ipinfo.io/json' because it violates the document's Content Security Policy.

Error #4 - relating to fetch call to external website

bundle.js:1  
Uncaught (in promise) TypeError: Failed to fetch
    at HTMLDocument.<anonymous> (bundle.js:1)
    at u (bundle.js:25)
    at l (bundle.js:25)

Other approaches

For reference, here is one of the other approaches I tried using a nonce:

I added this to entry.js:

__webpack_nonce__ = 'something-tricky';

And this to the <head> section of the index file:

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'nonce-something-tricky';

The result was that it wouldn't load bundle.js:

Refused to load the script 'http://localhost:3000/js/bundle.js' because it violates the following Content Security Policy directive: "script-src 'nonce-something-tricky'". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.

This approach was based on:

https://webpack.js.org/guides/csp

https://stackoverflow.com/a/42924000

Further context

As i started trying all sorts of CSP combinations in the <head> section, I noticed it started breaking lots of things like:

  • script tag links in index.html to google fonts etc
  • css styles generated and included in bundle.js

So i'm aware of the need to get CSP completely right, or it won't work at all.

Edit

My last attempt was this:

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' https://ipinfo.io; style-src 'self' fonts.googleapis.com 'unsafe-inline'; font-src 'self' fonts.gstatic.com">

And I am getting this error:

bundle.js:25 Refused to load the script 'https://ipinfo.io/json?callback=jQuery35106635073412967416_1598793439782&_=1598793439783' because it violates the following Content Security Policy directive: "script-src 'self'". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.

When this code is in the entry.js file:

$.get("https://ipinfo.io/json", function(response) {
  console.log(response);
}, "jsonp"); 

That last error is weird, because it seems to be ignoring the domain that I specifically 'whitelisted' in the srcipt-src directive.

4
  • You don't need to set CSP here. The root cause is that you don't have privilege to call ipinfo.io/json from your website. You need to call it by JSONP ipinfo.io/developers#jsonpcors-requests, or put the calls to your backend. Commented Aug 29, 2020 at 16:52
  • I used the code snippet at the link you shared, i just modified the url from https://ipinfo.io?token=$TOKEN to https://ipinfo.io/json (as i don't want to sign up for an account yet in order to get a token), and i removed any content security policy from index.html and I get this error: Refused to load the script 'https://ipinfo.io/json?callback=jQuery35108965288122289881_1598790072238&_=1598790072239' because it violates the following Content Security Policy directive: "script-src 'self'". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback. Commented Aug 30, 2020 at 12:25
  • Answer added, the issue was related to usage of helmet in node. Commented Aug 30, 2020 at 22:40
  • The default CSP would allow script-src from anywhere *. As I mentioned, the root cause is cross domain issue (JSOP should work), not CSP itself. Commented Aug 31, 2020 at 2:02

1 Answer 1

1

Ok, well i looked at the Network tab in Chrome developer tools for other requests and saw a rather rich set of CSP directives were being applied in the Response Headers tab, but i hadn't set them, so I wondered where they were coming from.

I came across this answer, which mentioned that they could be set using helmet in node

So in my node app, I replaced:

app.use(helmet());

which at the time of this edit is equivalent to this:

app.use(helmet.contentSecurityPolicy());
app.use(helmet.dnsPrefetchControl());
app.use(helmet.expectCt());
app.use(helmet.frameguard());
app.use(helmet.hidePoweredBy());
app.use(helmet.hsts());
app.use(helmet.ieNoOpen());
app.use(helmet.noSniff());
app.use(helmet.permittedCrossDomainPolicies());
app.use(helmet.referrerPolicy());
app.use(helmet.xssFilter());

where helmet.contentSecurityPolicy() defaults to:

default-src 'self';
base-uri 'self';
block-all-mixed-content;
font-src 'self' https: data:;
frame-ancestors 'self';
img-src 'self' data:;
object-src 'none';
script-src 'self';
script-src-attr 'none';
style-src 'self' https: 'unsafe-inline';
upgrade-insecure-requests

with:

app.use(
    helmet({
        contentSecurityPolicy: {
            directives: {
                defaultSrc: ["'self'"],
                scriptSrc: ["'self'", "https://ipinfo.io"],
                styleSrc: ["'self'", "fonts.googleapis.com", "'unsafe-inline'"],
                fontSrc: ["'self'", "fonts.gstatic.com"]
            }
        },
    })
);

and now this request from entry.js is working:

$.get("https://ipinfo.io/json", function(response) {
  console.log(response);
}, "jsonp"); 

Note, I had to add unsafe-inline to the StyleSrc or else the CSS that was imported and bundled into bundle.js using webpack wouldn't work.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.