I have server on which I start BrowserSync proxy from CLI (code bellow), the proxied url has some content-security-policy headers set
Browser error:
browser-sync-client.js?v=2.17.5:2Refused to connect to 'wss://joe.dev:10000/browser-sync/socket.io/?EIO=3&transport=websocket&sid=IJFLKqUjWn-BQrnnAAAA' because it violates the following Content Security Policy directive: "default-src data: https: 'unsafe-inline' 'unsafe-eval'". Note that 'connect-src' was not explicitly set, so 'default-src' is used as a fallback.
CSP headers set on proxied url:
content-security-policy:default-src data: https: 'unsafe-inline' 'unsafe-eval'; report-uri /csp-report
I have control over the proxied url html so I could add <meta http-equiv="Content-Security-Policy"> tag but so far I had no luck with making it work. Ideally it would only allow urls that BrowserSync needs and nothing more.
#!/bin/bash -eu
./node_modules/.bin/browser-sync start \
--proxy "https://page.dev" \
--port 10000 \
--ui-port 10001 \
--cors \
--no-open
./start.sh
Ok, I have figured it out. Probably not possible in CLI, but in nodejs interface you are able to alter the response of the proxied request - so what I did is I added little CSP parser and if CSP header is present, I add BrowserSync's wss url into the header.
For anybody interested here is code snippet that fixes the problem
'use strict'
const bs = require('browser-sync').create()
const CspParse = require('csp-parse')
bs.init({
proxy: {
target: 'https://page.dev',
proxyRes: [
function (proxyRes, req, res) {
const cspHeader = proxyRes.headers['content-security-policy']
if (!cspHeader) return
const newCsp = new CspParse(cspHeader)
// wss url which browser sync uses to communicate between devices,
// CPS headers could block this url so add it to allowed urls
const url = 'wss://' + req.headers.host
newCsp.add('default-src', url)
const newCspString = newCsp.toString()
proxyRes.headers['content-security-policy'] = newCspString
}
]
},
port: 10000,
ui: {
port: 10001
}
})
This whole thing could probably be integrated into the Browser-Sync to make proxying even easier (behind some flag)
@Hurtak so clutch you should work for Toyota. Thank you.
I came upon the issue while using lite-server and built upon @Hurtak 's answer to solve this issue with middleware:
const CspParse = require('csp-parse');
module.exports = {
https: true,
server: {
baseDir: "./dist",
middleware: {
2: function (req, res, next) {
const origHeaders = req.headers;
const cspHeader = origHeaders['content-security-policy'];
const url = 'https://' + req.headers.host;
const websocket = 'wss://' + req.headers.host;
if (cspHeader) {
const newCsp = new CspParse(cspHeader);
// wss url which browser sync uses to communicate between devices,
// CPS headers could block this url so add it to allowed urls
newCsp.add('default-src', `'unsafe-inline' ${url} ${websocket}`);
const newCspString = newCsp.toString();
res.setHeader('content-security-policy', newCspString);
} else {
const newCsp = new CspParse('script-src', `'unsafe-inline' ${url} ${websocket}`);
newCsp.add('default-src', `'unsafe-inline' ${url} ${websocket}`);
const newCspString = newCsp.toString();
res.setHeader('content-security-policy', newCspString);
}
next();
}
}
}
}
Most helpful comment
Ok, I have figured it out. Probably not possible in CLI, but in nodejs interface you are able to alter the response of the proxied request - so what I did is I added little CSP parser and if CSP header is present, I add BrowserSync's wss url into the header.
For anybody interested here is code snippet that fixes the problem
This whole thing could probably be integrated into the Browser-Sync to make proxying even easier (behind some flag)