React app served with express and helmet cannot make API requests - node.js

I am serving a react app build using express.
const root = path.join(__dirname, 'build/');
app.use(express.static(root));
app.use((req, res, next) => {
if (req.method === 'GET' && req.accepts('html') && !req.is('json') && !req.path.includes('.')) {
res.sendFile('index.html', { root });
} else next();
});
Everything works as intended. However as soon as i add helmet (NOT react-helmet) to the express app, I get issues (styles and scripts didn't load).
After searching several resources I was able to come up with a solution to make it work.
The below code shows the fix i did to make the styles and scripts load.
app.use(helmet());
app.use(helmet.contentSecurityPolicy({
defaultSrc: [
'\'self\'',
'https://api.domain.tld/*',
'https://domain.tld',
],
styleSrc: [
'\'self\'',
'\'unsafe-inline\'',
'https://*.googleapis.com',
'https://api.domain.tld/*',
'https://domain.tld',
],
scriptSrc: [
'\'self\'',
'\'unsafe-inline\'',
'https://api.domain.tld/*',
'https://domain.tld',
],
contentSrc: [
'\'self\'',
'\'unsafe-inline\'',
'https://api.domain.tld/*',
'https://domain.tld',
],
}));
Additionally I also included INLINE_RUNTIME_CHUNK=false in the .env file.
The issue I have currently is that the API calls I am making to api.domain.tld does not work. It gets blocked and the following errors show up on firefox.
Content Security Policy: The page’s settings blocked the loading of a resource at https://api.domain.tld/endpoint (“default-src”).
Chrome shows the following error.
Refused to connect to 'https://api.domain.tld/endpoint' 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.
Please note that the react app is on domain.tld and the API is on api.domain.tld
How can if fix this issue so I can make API calls?

There is 2 issues:
Do fix a syntax error: contentSrc: -> connectSrc:
CSP spec does not allow using * (wildcard) in the path-part, therefore do fix 'https://api.domain.tld/* -> 'https://api.domain.tld/'. Also in the path-part you can use:
a folder name: 'https://api.domain.tld/real_path_here/' (with trailing slash /) - will allow any subfolders and any files in specified folder and subs.
file name: 'https://api.domain.tld/endpoint' or 'https://api.domain.tld/some_path/script.js' (without trailing slash /) - will allow specified file_name only.

According to the Documentation, You should specify sources inside the directives
app.use(helmet.contentSecurityPolicy({
useDefaults: false, // you can change it to `true` if you want.
directives:{
defaultSrc: [
'\'self\'',
'https://api.domain.tld/',
'https://domain.tld',
],
styleSrc: [
'\'self\'',
'\'unsafe-inline\'',
'https://*.googleapis.com',
'https://api.domain.tld/',
'https://domain.tld',
],
'image-src': [
'\'self\'',
'\'unsafe-inline\'',
'data:',
'https://api.domain.tld/',
'https://domain.tld',
],
scriptSrc: [
'\'self\'',
'\'unsafe-inline\'',
'https://api.domain.tld/*',
'https://domain.tld',
],
contentSrc: [
'\'self\'',
'\'unsafe-inline\'',
'https://api.domain.tld/',
'https://domain.tld',
],
}
}));
Update
To fix the image not loading issue, Add the following.
imageSrc: [
'\'self\'',
'\'unsafe-inline\'',
'data:',
'https://api.domain.tld/',
'https://domain.tld',
],

Related

Helmet: How to allow images to load from different domain (Err: NotSameOriginAfterDefaultedToSameOriginByCoep)

I am using helmet to set CSP headers. I am using React on the frontend.
I store my images on a subdomain (assets.mydomain.com). For some reason I get the following error message: ERR_BLOCKED_BY_RESPONSE.NotSameOriginAfterDefaultedToSameOriginByCoep when loading the images.
I also use a script tag for Google Analytics. This one also gives me an error message: Refused to connect to https://www.google-analytics.com/ because it violates... "default-src 'self'"
This is how I have configured my CSP currently:
app.use(
helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: [
"'self'",
"https://www.googletagmanager.com",
"'self'",
"https://www.google-analytics.com",
"'unsafe-inline'",
"mydomain.com",
],
imgSrc: ["'self'", "assets.mydomain.com"],
},
},
crossOriginEmbedderPolicy: false,
crossOriginResourcePolicy: false,
})
);
What is wrong with my CSP configuration?
So if anyone comes across this question for some reason, I figured it out. As it turns out, the cross-origin-embedder-policy header was giving me troubles. This had to be disabled. Helmet has a built in option to do so crossOriginEmbedderPolicy: false,. More info here.
For most people I guess that'll work. However it did not work for me. The header was still being set. Disabling it with express also did not work (app.disable('cross-origin-embedder-policy');).
I have no idea why the header was still being set, but I had to disable it manually in my nginx configuration: proxy_hide_header cross-origin-embedder-policy;
My config:
app.use(
helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: [
"'self'",
"'unsafe-inline'",
"https://*.google.com",
"https://*.google-analytics.com",
"https://*.googletagmanager.com",
"https://*.hotjar.com",
"https://*.mollie.com",
],
connectSrc: [
"'self'",
"'unsafe-inline'",
"https://*.google.com",
"https://*.google-analytics.com",
"https://*.googletagmanager.com",
"https://*.hotjar.com",
"https://*.mollie.com",
],
imgSrc: [
`'self'`,
`data:`,
`*.domain.nl`,
`*.amazonaws.com`,
],
},
},
//Will work for most, but did not work for me:
// crossOriginEmbedderPolicy: false,
})
);
//# in nginx I manually disabled the COEP header: roxy_hide_header cross-origin-embedder-policy;
I did it!!!
After literally hundreds of test-error I found that this little piece of code at least, it fixed my problem of having 2 different services (2 domains) and now my little app is working fine again, time 1:11am !! :)
app.use(
helmet({
contentSecurityPolicy: {
directives: {
scriptSrc: ["'self'", 'www.google.com www.gstatic.com',"https://*.statcounter.com", "'unsafe-inline'"],
frameSrc: ["'self'", "www.google.com", "https://*.statcounter.com"],
connectSrc: ["'self'", 'https://*.statcounter.com'],
},
},
crossOriginResourcePolicy: { policy: "cross-origin" },
crossOriginEmbedderPolicy: false,
})
);

uploading asset to strapi with cloudinary gives error : ENOTEMPTY: directory not empty

I was following this tutorial to create a web app that uses Cloudinary as a image host , I followed all the steps mentioned in it but when i try to add a image it gives me this error ErrorImage , idk what's causing this , is this some kind of connection error ?
here is my plugins.js
module.exports = ({ env }) => ({
upload: {
config:{
provider: 'cloudinary',
providerOptions: {
cloud_name: env('+++++++'),
api_key: env('8+++++++++++'),
api_secret: env('1T++++++++++++U'),
},
},
my .env file , this file also contains other stuff like jwt keys , host , port etc , here is what i added to it
--hosts ports etc--
CLOUDINARY_NAME = **********
CLOUDINARY_KEY = ***********
CLOUDINARY_SECRET = ***************
my middleware.js file
module.exports = [
'strapi::errors',
{
name: 'strapi::security',
config: {
contentSecurityPolicy: {
useDefaults: true,
directives: {
'connect-src': ["'self'", 'https:'],
'img-src': ["'self'", 'data:', 'blob:', 'res.cloudinary.com'],
'media-src': ["'self'", 'data:', 'blob:', 'res.cloudinary.com'],
upgradeInsecureRequests: null,
},
},
},
},
'strapi::cors',
'strapi::poweredBy',
'strapi::logger',
'strapi::query',
'strapi::body',
'strapi::session',
'strapi::favicon',
'strapi::public',
];

Refused to frame 'https://pagead2.googlesyndication.com/' because it violates the following Content Security Policy

I implemented adsense, but I have the following error message printed in the console when loading a webpage with ads on. Thing is it loads this error message sometimes, not every time I reload the same page.
Refused to frame 'https://pagead2.googlesyndication.com/' because it
violates the following Content Security Policy directive: "frame-src
cm.g.doubleclick.net googleads.g.doubleclick.net www.google.com
accounts.google.com
pagead2.googlesyndication.com/pagead/s/cookie_push.html gmsg:
https://tpc.googlesyndication.com/sadbundle/..."
I have the following CSP policies set on my Node server :
app.use(
helmet.contentSecurityPolicy({
useDefaults: true,
directives: {
defaultSrc: ["'self'"],
scriptSrc: [
"'self'",
'googleapis.com',
],
objectSrc: ["'none'"],
frameSrc: [
"'self'",
'https://pagead2.googlesyndication.com/',
'cm.g.doubleclick.net',
'googleads.g.doubleclick.net',
'www.google.com',
'accounts.google.com',
'https://adservice.google.com/',
'https://tpc.googlesyndication.com/',
],
},
})
);
Any idea what I am missing ?

script-src-elem is blocked athough being defined in script-src in Windows 10 (Chrome)

We are trying to implement Content security policy in our web application. Our application stack is MERN.Using helmet package we are trying to implement Content security policy in node js .
Currently We have enabled reportOnly mode in production for testing purpose and facing this error only in our production not in development or staging environments. Effective-attribute is script-src-elem and user agent is Window 10 chrome user-agent. We are confused how to proceed with this error as it impacting on our own script and some other valid sources randomly.We are confused whether to enforce CSP in production or not?
I'm facing a issue. script-src-elem is blocked although defined in script-src.
I am using node js . Using helmet package,we have configured csp.my csp list for reference is -
app.use(
helmet.contentSecurityPolicy({
reportOnly: true,
setAllHeaders: false,
directives: {
defaultSrc: ['*', 'data:', 'ws:'],
imgSrc: [
'*.sample.com',
'https:',
'blob:',
'data:' ],
styleSrc: [
"'self'",
"'unsafe-inline'",
'assets.sample.com',
'https://fonts.googleapis.com',
'https://accounts.google.com',
'data:',
'blob:',
],
scriptSrc: [
"'self'",
"'unsafe-inline'",
"'unsafe-eval'",
'data:',
'blob:',
'https://*.sample.com',
'https://*.google-analytics.com',
'https://*.facebook.net',
'https://*.google.com',
],
],
frameAncestors: ["'self'"],
workerSrc: ["'self'", 'blob:'],
objectSrc: ["'none'"],
reportUri: '/violation',
},
}),
);
I'm facing csp violation under script-src-elem for url https://assets.sample.com/build/resultpage.9cff494c01ced7b4.chunk.js , https://connect.facebook.net. I am not aware what mistake has been commited in the configuration. Can somenone help us out!!! Thanks in advance.
I am not sure if you have defined your strings correctly. You are giving the protocol prefix of the url in the string and I believe that isn't correct. Entries like
scriptSrc: [
"'self'",
"'unsafe-inline'",
"'unsafe-eval'",
'data:',
'blob:',
'https://*.sample.com',
'https://*.google-analytics.com',
'https://*.facebook.net',
'https://*.google.com',
],
should probably be
scriptSrc: [
"'self'",
"'unsafe-inline'",
"'unsafe-eval'",
'data:',
'blob:',
'*.sample.com',
'*.google-analytics.com',
'*.facebook.net',
'*.google.com',
],
Try that and see if it helps

Content Security Policy: The page’s settings blocked the loading of a resource at data:image/svg+xml;base64,PHN2ZyB3aWR0aD… (“default-src”)

I am trying to add a paypal button, but the image doesnt load and gives the below error
Content Security Policy: The page’s settings blocked the loading of a resource at data:image/svg+xml;base64,PHN2ZyB3aWR0aD… (“default-src”)
Below is my meta code
<meta http-equiv="Content-Security-Policy" content="default-src * 'data'; img-src: *; style-src 'self' 'unsafe-inline' https://* http://*; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://* http://*" />
I have many external scripts/css/images which are loaded and i want allow everything to load without getting blocked.
Any help will be appreciated
You have defined img-src with just * which will include everything HTTP or HTTPS depending on your connection. 'data' will not be included. You will need to include data: (with the colon but without quotes) to img-src. You have included 'data' in default-src, but as you have defined img-src this fallback will not be used. Also check your syntax as pointed out by #sideshowbarker.
I recommend you to use helmet library instead of hard-coding security headers in your head tag even if having master pages. After that you can check if your headers are now secured on https://securityheaders.com/.
In case of nodejs my implementation looks like following:
const helmet = require('helmet');
app.use(
helmet.contentSecurityPolicy({
useDefaults: false,
"block-all-mixed-content": true,
"upgrade-insecure-requests": true,
directives: {
"default-src": [
"'self'"
],
"base-uri": "'self'",
"font-src": [
"'self'",
"https:",
"data:"
],
"frame-ancestors": [
"'self'"
],
"img-src": [
"'self'",
"data:"
],
"object-src": [
"'none'"
],
"script-src": [
"'self'",
"https://cdnjs.cloudflare.com"
],
"script-src-attr": "'none'",
"style-src": [
"'self'",
"https://cdnjs.cloudflare.com",
"https://fonts.googleapis.com"
],
},
}),
helmet.dnsPrefetchControl({
allow: true
}),
helmet.frameguard({
action: "deny"
}),
helmet.hidePoweredBy(),
helmet.hsts({
maxAge: 123456,
includeSubDomains: false
}),
helmet.ieNoOpen(),
helmet.noSniff(),
helmet.referrerPolicy({
policy: [ "origin", "unsafe-url" ]
}),
helmet.xssFilter()
);
More info about these filters can be found on https://helmetjs.github.io/

Resources