I am working on a web application with a React frontend and a NestJS backend. The backend uses Helmet to manage the Content Security Policy (CSP).
My frontend needs to connect to an API hosted on a physical scanner with a dynamic IP address (assigned via DHCP). The scanner's IP address is stored in the database and fetched dynamically by the frontend.
import helmet from 'helmet'
const defaultDirectives = helmet.contentSecurityPolicy.getDefaultDirectives()
app.use(
helmet({
contentSecurityPolicy: {
useDefaults: true,
reportOnly: false,
directives: {
...defaultDirectives,
'connect-src': ["'self'", '172.x.x.x'], // Static IP set here
'script-src': ["'self'", '*.openstreetmap.org'],
'img-src': ["'self'", 'data:', 'blob:', '*.openstreetmap.org'],
'style-src': ["'self'", "'unsafe-inline'", 'fonts.googleapis.com'],
'font-src': ["'self'", 'fonts.gstatic.com']
}
},
crossOriginEmbedderPolicy: false,
crossOriginOpenerPolicy: false,
crossOriginResourcePolicy: false,
})
)
When the scanner's IP address changes (e.g., from 172.x.x.x
at work to 192.x.x.x
at home), I encounter the following error:
Refused to connect to 'http://192.x.x.x/api/connect' because it violates the following Content Security Policy directive: "connect-src 'self' 172.x.x.x".
It seems that the CSP configured in the backend is too restrictive, and I'm unsure how to set the IP address dynamically based on the scanner's changing IP.
Additionally, it feels like the backend's Helmet CSP configuration might be overriding the frontend's policy, leading to this issue.
connect-src
directive in CSP to allow the scanner's IP (172.x.x.x
), but this does not account for the dynamic nature of the scanner's IP address.connect-src
directive dynamically based on the IP stored in the database?connect-src
(e.g., using '*'
or 'unsafe-inline'
) be a valid approach without compromising too much security?Any insights or suggestions would be greatly appreciated! 😊
Helmet maintainer here. Let's answer your four questions.
To answer your first two questions, here's how you'd dynamically set the connect-src
directive.
I'd start by writing some generic middleware that stores the dynamic IP address. It might look something like this:
app.use((req, res, next) => {
res.locals.scannerIpAddress = dynamicallyFetchIpAddress();
next();
});
Then you can set the Content-Security-Policy dynamically:
app.use(
helmet({
contentSecurityPolicy: {
// ...
directives: {
...defaultDirectives,
"connect-src": [
"'self'",
(req, res) => res.locals.scannerIpAddress,
],
// ...
},
},
// ...
}),
);
Your third question is about disabling connect-src
entirely. This could impact security because a rogue script could connect to some malicious server. However, it's up to you whether that's an acceptable risk.
Your final question is about best security practices while allowing these dynamic connections. You'd want to make sure that the scanner IP address is safe and correct.