.. title: Security headers
.. slug: security-headers
.. date: 2018-09-08 10:48:31 UTC
.. tags: info, web
.. category: 
.. link: 
.. description: 
.. type: text

A few simple provisions were sufficient to `make this blog GDPR compliant <https://cobra.pdes-net.org/posts/general-data-protection-regulation.html>`_. Even less was required to get a `high rating regarding security <https://cobra.pdes-net.org/posts/lets-encrypt.html>`_. As a first step, I've obtained certificates from the Let's Encrypt initiative and configured Hiawatha (our web server) accordingly:

::

	VirtualHost {
		...
		TLScertFile = /etc/hiawatha/tls/pdes-net.org.pem
		RequireTLS = yes, 31536000; includeSubDomains; preload
		...
	}

This configuration got an `A+ <https://cobra.pdes-net.org/posts/lets-encrypt.html#>`_ rating from `Qualys SSL labs <https://www.ssllabs.com>`_.

However, there's more to the security of a website than transport encryption. For example, the `Content Security Policy <https://en.wikipedia.org/wiki/Content_Security_Policy>`_ “provides a standard method for website owners to declare approved origins of content that browsers should be allowed to load on that website”. There are actually a number of these security headers, and after some research I came up with the following settings:


::

	VirtualHost {
		...
		CustomHeader = Vary: Accept-Encoding
		CustomHeaderClient = X-Frame-Options: sameorigin
		CustomHeaderClient = X-XSS-Protection: 1; mode=block
		CustomHeaderClient = X-Content-Type-Options: nosniff
		CustomHeaderClient = X-Robots-Tag: none
		CustomHeaderClient = X-Permitted-Cross-Domain-Policies: none
		CustomHeaderClient = Referrer-Policy: same-origin
		CustomHeaderClient = Expect-CT: enforce; max-age=3600
                CustomHeaderClient = Content-Security-Policy: frame-src 'self'; worker-src 'self'; connect-src *; default-src 'self'; img-src 'self' data: chrome-extension-resource:; font-src 'self' data:; object-src 'self'; media-src 'self' data:; manifest-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; base-uri 'none'
		...
	}

The CSP proved to be tricky since Chromium did not display images in SVG format with stricter settings. A post of `April King <https://pokeinthe.io/2016/04/09/black-icons-with-svg-and-csp/>`_ finally provided the missing piece of the puzzle. Furthermore, MathJax only works in my implementation if I allow scripts and styles to be included 'unsafe-inline'. As a result of this latter setting, my current configuration achieves only a 'B+' instead of the 'A+' depicted below. 

Update: I've cleaned up and simplified the CSP, which now reads


::

                CustomHeaderClient = Content-Security-Policy: frame-ancestors 'none'; frame-src 'self'; default-src 'self'; object-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; base-uri 'none'; form-action 'none'

That still gets a 'B+' because of the 'unsafe-inline' options. 


`Mike Kuketz <https://www.kuketz-blog.de/online-scanner-tools-fuer-sicherheit-und-datenschutz/>`_ listed a number of online scanners evaluating the implementation of security policies on arbitrary web sites. One of the most informative one of these tools is `Mozilla's observatory, <https://observatory.mozilla.org/>`_ developed by the same `April <https://pokeinthe.io/2016/08/25/observatory-by-mozilla-a-new-tool/>`_ whose post had helped me with the CSP. ☺

.. image:: ../images/observatory.png
   :align: center
