Apache 'Header set' functions differently across browsers

I am running a self-hosted Nextcloud installation on Apache behind HAproxy.

I encountered an error with the fonts, similar to what is described in this forum post. As a remedy, it is suggested to alter the Content-Security-Policy like so:

<IfModule mod_headers.c>
    Header set Content-Security-Policy: "font-src https: data:;"
    # `mod_headers` cannot match based on the content-type, however,
    # the `Content-Security-Policy` response header should be send
    # only for HTML documents and not for the other resources.
    <FilesMatch "\.(appcache|atom|bbaw|bmp|crx|css|cur|eot|f4[abpv]|flv|geojson|gif|htc|ico|jpe?g|js|json(ld)?|m4[av]|manifest|map|mp4|oex|og[agv]|opus|otf|pdf|png|rdf|rss|safariextz|svgz?|swf|topojson|tt[cf]|txt|vcard|vcf|vtt|webapp|web[mp]|webmanifest|woff2?|xloc|xml|xpi)$">
        Header unset Content-Security-Policy
    </FilesMatch>
</IfModule>

However, this has an effect I cannot explain. If I access Nextcloud through Firefox/Chrome, there are two Content-Security-Policy headers:

Chrome/Firefox CSP headers

This causes the 'Content-Security-Policy: font-src https: data:;' header to be ignored as it is less restrictive, from my understanding. The issue I encounter persists.

However, if I access Nextcloud through IE, I see a single header:

Content-Security-Policy: font-src https: data:;, default-src 'self'; script-src * 'unsafe-inline' 
'unsafe-eval'; style-src * 'unsafe-inline'; img-src * 'unsafe-inline' data:; font-src *;
 object-src 'self';media-src 'self'; frame-src 'self';

In this case, the issue is resolved and fonts are loaded.

What could be causing a second header to appear in Chrome/Firefox? How can I resolve this issue?


Solution 1:

It seems that IE is combining the two values of Content-Security-Policy, while the other browsers don't, and this leads to different behavior. But the problem is that the header is being set twice. A couple of options:

  1. Find the other place in your configuration where Content-Security-Policy is being set, and remove that.

  2. Your header value is being set with the onsuccess condition (the default), so the other value must be getting set with the always condition. See Header. Apache merges the two lists and sends them both. So you can either clear the value in the always condition:

     Header always unset Content-Security-Policy
     Header onsuccess set Content-Security-Policy "font-src https: data:;"
    

    or replace the value in always with yours:

     Header always set Content-Security-Policy "font-src https: data:;"
    

Solution 2:

After some more digging, I believe I have found an answer.

It turns out that HAproxy was adding security-related headers to requests that were going through it. That was causing the duplication. The different behaviour of the browsers was a symptom since the CSP header was specific to Chrome.

The issue was fixed by introducing different CSP headers that could be parsed by different browsers in HAproxy. This has also fixed the original issue with fonts not loading.

Thanks to Andrew for help with this issue as well.