Search code examples
.htaccesshtml5boilerplatemod-headers

Why `mod_headers` cannot match based on the content-type?


I can't get my mind wrapped around the comments and way of coding, to set a header only for .html in for example the .htaccess file in html5 boilerplate.

The clue for a big codeblock lays in the fact that 'mod_headers can't match on the content type' (as # commented). So I wander 1: why is there a 'Header unset' in a <FilesMatch>, that just has been announced to be impossible?

<IfModule mod_headers.c>  

   Header set Content-Security-Policy "script-src 'self'; object-src 'self'"  

   # `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]|woff2?|xloc|xml|xpi)$">
     Header unset Content-Security-Policy
   </FilesMatch>  

</IfModule>  

I looked everywhere, but only land on pages that have the same, almost ritual used codeblock, without further explanation. So question 2: why is a simple declaration like this not possible?:

<IfModule mod_headers.c>

  # Content-Security-Policy for .html files
  <FilesMatch "\.(html)$">
    Header set Content-Security-Policy "script-src 'self'; object-src 'self'"
  </FilesMatch>

  # OR like this 
  <Files ~ "\.(html)$">
    Header set Cache-Control "public, must-revalidate"
  </Files>  

</IfModule>

Solution

  • It is possible to do that as per your second example. But .html are not the only files that could be sent as documents. You could also use .php or .htm or any other number of files. Some of these (like .php) may execute and then ultimately return HTML but the server doesn't know that as all it knows at this stage is the file extension.

    CSP should be set on all documents but, to save header bandwidth, does not need to be set on assets used by those documents (e.g. images, style sheets, javascript... etc). Other than wasted bandwidth there is no really harm in setting it on other documents.

    Ideally you would set it based on the mime-type returned (which in the PHP example above would be HTML). So anytime a HTML document is returned then set it, else don't. However as this is not possible you're left with two choices:

    1. Set it on everything by default but then explicitly unset it for known media types. This pretty much guarantees it will be set on the document but also risks it being set on a few other file types (e.g. if you don't explicitly unset it for that type) - which, as I say isn't really that bad.

    2. Explicitly state your HTML document types (like your second example). The risk here is you miss a file type (e.g. .php) either now or when someone else starts using php on your site in future.

    The first option is the safer option. Particularly for html5boiler plate where they have no idea what technology will be used on the site it's used on. A site might use .php, .cgi, .asp or any number of technologies to generate the HTML document. They could even proxy the request to a back end server so they would be no file extension.

    Make sense?