3

I have a online whiteboard that Safari users cannot connect to. They get the following from the console.

Refused to connect to wss://whiteboard.[MYDOMAIN].com/[MOREPATHSTUFF] because it does not appear in the connect-src directive of the Content Security Policy.

Only Safari does this. Chrome, FF, Edge, etc. work fine. I've looked over other SO related posts and it seems that Safari requires something like...

<meta http-equiv="Content-Security-Policy" content="
                        default-src * data: blob: ws: wss: gap://ready file://*;
                        style-src * 'unsafe-inline'; 
                        script-src * 'unsafe-inline' 'unsafe-eval';
                        connect-src * ws: wss:;">

I have no idea what all of this means though. All I want is for Safari to allow the connection and all should be well. Thanks for the consideration on how to make that happen.

gtilflm
  • 1,389
  • 1
  • 21
  • 51

2 Answers2

2

I've looked over other SO related posts and it seems that Safari requires something like...

You already have a Content Security Policy (CSP) been published via an HTTP header or meta tag (how to check it), because a violation message appears in the browser console.
Publishing the second CSP cannot relax the resulting policy, since the first CSP will still perform a blocking.
That's why you couldn't fix the problem by adding a meta tag or HTTP header.

You have to figure out where the first CSP is published and to make changes to it.

Only Safari does this. Chrome, FF, Edge, etc. work fine.

Safari supports the connect-src directive, so its behaviour should not differ from Chrome/Firefox/Edge except one thing: Safari does not support upgrade ws: to wss:.
In case of connect-src ws:, the Chrome/Firefox/Edge will apply connect-src ws: wss: policy, but Safari does not.

I bet you have connect-src ws: in the CSP, therefore all connection to wss: are blocked.
When you find where your CSS is published, just add wss://whiteboard.[MYDOMAIN].com to connect-src directive.

Note: if you are using the default-src directive instead of connect-src - then you need to add wss://whiteboard.[MYDOMAIN].com into it.

Update:
How CSP header can be issued

A). A CSP header can be published in your web app itself (Helmet middleware, specific packages for managing HTTP headers, direct issue an HTTP header via res.setHeader() and so on).

B). CSP header can be published by server. For Nginx it should be add_header Content-Security-Policy "default-src ... "; in the server config. Several folders can be used for that but etc/nginx/conf.d is preferred, others are deprecated.

What if I publishes CSP header in both ways A) and B) at the same time?

Server works after your web app software did all job, therefore web-server (or proxy-server) should override an HTTP header with the same name. So server can override any HTTP header published by web app.

In some cases it's not work and you can see that 2 CSP headers been published. Even in this case you can make a trick:

proxy_hide_header Content-Security-Policy;

and then immediately under that, add header how fo you need it:

add_header Content-Security-Policy "default-src 'self';";

This can be used as a temporary solution until you figure out where the header is really published.

Mario Petrovic
  • 7,500
  • 14
  • 42
  • 62
granty
  • 7,234
  • 1
  • 14
  • 21
  • Good catch!! I found `content-security-policy: connect-src 'self';` in Response Headers. Now..... how to find where that's being set. We're using Vue.js 3 for this and I've searched all files for `content-security-policy`. Nothin'. Do you have any ideas on where I should look for this sort of thing on the server? I have access to PuTTY, but I don't know many commands for it. – gtilflm Aug 15 '21 at 01:22
  • 1
    It's strange, because `connect-src 'self'` should not allow `wss://whiteboard.[MYDOMAIN].com` in Chrome/FF/Edge, unless the page is loaded from the `https://whiteboard.[MYDOMAIN].com`. But Safari has a bug with `'self'` too - it covers `http:/https:` but not `ws:/wss:` unlike other browsers. CSP Responce header can be set in Nginx config, try to search `add_header Content-Security-Policy "default-src 'self'; connect-src 'self'"` string. In case of `Node.js` server, a CSP header can be set by some packages like [Helmet](https://helmetjs.github.io/), `csp-header`, `node-csp` etc. – granty Aug 15 '21 at 09:07
  • Found two "clusters". 1.) Three different `.conf` files in `/etc/nginx/sites-enabled` have references to `add_header Content-Security-Policy "connect-src 'self';";`. I tried changing them all, but nothing ever changed in the response headers area. 2.) Several things like `res.setHeader('Content-Security-Policy', "default-src 'none'")` in a handful of files that seem to be related to node.js. #1 seems more promising though becase of the `connect-src 'self';` part. Thoughts? – gtilflm Aug 15 '21 at 14:46
  • 2.) `res.setHeader('Content-Security-Policy', "default-src 'none'")` belongs a built-in NodeJS [finalhandler](https://github.com/pillarjs/finalhandler/issues/26) for non-existent pages with code 404/403, etc. It publishes its own restrictive CSP for security reasons, pls do not change its CSP. 1.) I have added some related info into the answer. – granty Aug 15 '21 at 20:53
  • Got it working! The issue was that I didn't know you had to restart the nginx service after making a change. So, it's possible that earlier changes would have worked, but for future finders of this question, here's what worked. Adding `wss://whiteboard.[MYDOMAIN].com;";` into the CSP found in a .conf file in `etc/nginx/`. The full CSP line is `add_header Content-Security-Policy "connect-src 'self' wss://whiteboard.[MYDOMAIN].com;";`. Thanks granty!! – gtilflm Aug 15 '21 at 23:31
  • add_header Content-Security-Policy "default-src 'self';"; – cmac Jan 11 '22 at 22:28
0

CSP has some unintuitive traits. One is: Websockets like wss://example.com are not captured by wildcards such as *.example.com or even *

In order to allow the websockets - you need to explicitly add them with wss://example.com or even ws: wss:

If you only want to allow anything on the connect-src, then adding connect-src * ws: wss:; to your policy should work (as you mentioned).

Shai Alon
  • 18
  • 6
  • I'm just trying to get past Safari's error. Based on your answer, should the following work? `` – gtilflm Aug 12 '21 at 00:23
  • Yes. Do note that safari has unique behaviour with regards to the `/[MOREPATHSTUFF]`. In some versions it gets stripped out or the CSP report - making it very hard to debug. Since `connect-src` is not a mission-critical directive (like `script-src`, `form-src`, `base-uri`), I would suggest not adding the path granularity and keeping `connect-src wss://whiteboard.[MYDOMAIN].com;` Also - are you able to set your CSP via HTTP response headers instead of an HTML meta tag? This approach is would be more convenient - supporting `Content-Security-Policy-Report-Only` and more directives. – Shai Alon Aug 12 '21 at 06:56
  • I don't know about doing HTTP response headers. I'd have to get with someone about that. Also, I tried `` and Safari gave the same error as before. Am I missing anything? – gtilflm Aug 12 '21 at 15:16
  • I've tried other iterations and nothing is working. `` and `` have both failed. – gtilflm Aug 12 '21 at 17:07
  • I would like to see an example of the same CSP applied via an HTTP header, and not a meta tag, and check if the issue persists. – Shai Alon Aug 13 '21 at 12:34
  • I tried creating an .htaccess file and adding `Header set Content-Security-Policy "connect-src 'self' [MYDOMAIN].com *.[MYDOMAIN].com;"`. I don't see anything in "Response" in the Network tab though. That makes me think it's not even being applied. Also, it looks like Nginx is installed on the server. Could that be related? – gtilflm Aug 13 '21 at 15:15
  • I don't have enough context to explain how to set HTTP headers for your specific setup. Sorry. – Shai Alon Aug 14 '21 at 09:17