Securing HTTP header for Apache HTTP servers on Linux

In this post, I am going to show you, how to increase the security of your webpage for your visitors. We will configure Apache to add more information in the HTTP header, which helps the browser to identify and block potential attacks.

But please keep in mind, that we just provide information such as which types of resource do we use (e.g. JavaScripts, CSSs, Fonts, and so on.) and where to get them (locations) but in the end, the browser decide whether it respects these information or just ignoring them. Commonly, the major browsers such as Chrome, Mozilla Firefox, Internet Explorer, Edge, Safari and similar, they do. Browsers, built for special needs such as for crawling informations, they usually don’t.

The Theory

I will start with talking about each single HTTP header item, that will help increasing the security, without any references to how to configure Apache to support it. After going through all of them, we will configure all the feature together. So if you are here just for the result, you can jump right to the next chapter instead of going through the following subchapters.

#1 Content-Security-Policy (CSP)

This item instruct the browser, which location(s) it is allowed to use for loading additional assets such as JavaScripts, CSS, images, fonts and so on. It also instruct the browser, which type of ressources it is allowed to use including inline scripts and inline styles.

The main purpose of this item is to prevent cross-site scripting (XSS) and other code injection attacks. By providing clear instructions and restrictions, you help the browser to block unwanted script execution and ultimately XSS attacks. The following item in the HTTP header would instruct the browser to only load resources from the same origin including URL scheme and port number.

Content-Security-Policy: default-src 'self'

Instead of ‘self’, you could use ‘unsafe-inline’, ‘unsafe-eval’ or other values (checkout this article). ‘unsafe-inline’ would mean, that the browser can run inline scripts.

Beside the default-src, there are many others such as script-src, style-src and so on. As the name success the default-src act as a fallback directive. E.g. If you don’t instruct anything specific for scripts, it will fall back to default-src. Check out this article to see the full list of all directives.

This item follows the whitelist approach. So if you do not specified explicitly then it is not allowed. Be as restrictive as possible.

Before the W3C published the standard, “X-Content-Security-Policy” and “X-WebKit-CSP” were used. But major modern browser has now switched to the W3C standard “Content-Security-Policy”. To check the browser support of CSP, click here.

#2 X-Frame-Options

This item is used to counter clickjacking, where a malicious website shows your website in an frame element and put a transparent overlay over it. When a user intents to click something on your page, the overlay would be activated instead.

By adding it to the HTTP header, you instruct the browser, that it should allow a page to be rendered inside a frame (<frame>, <iframe>, <embed> or <object>). Possible values are:

X-Frame-Options: deny
X-Frame-Options: sameorigin
X-Frame-Options: allow-from

Although with the frame-ancestors directives of the CSP, this directive is obsolete. But for backward compatibility you should still have it.

#3 X-XSS-Protection

Starting with IE8, Microsoft introduced a built-in feature known as XSS filter to mitigate reflected XSS. Later Webkit introduced a similar feature for Chrome and Safari. The idea is quite straightforward, the browser check whether a script, that it is about to run is also present in the request, that fetched that web page. If it is the case, it is a strong indication.

Depends on the following settings, the browser will act accordingly:

X-XSS-Protection: 0
X-XSS-Protection: 1
X-XSS-Protection: 1; mode=block

0 means, disabling the feature. 1, the default, would instruct the browser to remove the unsafe parts. And the last option is to completely block the rendering of the document. It is recommended based on previous vulnerabilities, to use the “all or nothing” strategy meaning last option.

Mozilla does not offer any similar feature because it believes, that having a good content security policy makes this feature unnecessary (see Mozilla documentation).

#4 X-Content-Type-Options

This is another HTTP header extension, that is introduced by Microsoft and later implemented by other vendors. It instructs the browser to follow the MIME type and do not change it.

X-Content-Type-Options: nosniff

If the MIME type is not correct, block the request. Safari does not support this item (see Mozilla documentation).

#5 Strict-Transport-Security

The Strict-Transport-Security header item (often abbreviated as HSTS) instructs the browser that it should stick to the HTTPS, instead of using the HTTP. Currently the following options are available:

Strict-Transport-Security: max-age=<seconds>
Strict-Transport-Security: max-age=<seconds> ; includeSubDomains
Strict-Transport-Security: max-age=<seconds> ; preload
Strict-Transport-Security: max-age=<seconds> ; includeSubDomains; preload

The first time, you visit a website using https with this item in the HTTP header, the browser will store this information. Every subsequent calls will automatically use HTTPS. Every visit to the page reset the age. Google is maintaining an HSTS preload service, which all browsers have stated the intent to use or are actually using.

By instructing the browser to stick to HTTPS, the user is less exposed to a man in the middle attack. You can register your page by clicking here.

To enhance the security of cookies, you can add several directives to the Set-Cookie items:

Set-Cookie: <cookie-name>=<cookie-value>; Secure 
Set-Cookie: <cookie-name>=<cookie-value>; HttpOnly 
Set-Cookie: <cookie-name>=<cookie-value>; SameSite=Strict 
Set-Cookie: <cookie-name>=<cookie-value>; SameSite=Lax 

You can use multiple directives at the same time:

Set-Cookie: <cookie-name>=<cookie-value>; Secure; HttpOnly; SameSite=Strict

The Secure directive instruct the browser to only share this cookie with HTTPS pages.

The HttpOnly directive instruct the browser, that this is not accessible via JavaScript through the Document.cookie property, XMLHttpRequest API or the Request API.

The SameSite directive instruct the browser, that it should not send the cookie along with cross-site requests. Hence, providing some protection against cross-site request forgery attacks (CSRF).

Configure Apache (>=2.2.4)

First you need to ensure, that your Apache web server has the header module enabled. If this is not the case, you can enable it using the following command:

sudo a2enmod headers

If you are not sure, just run it. It won’t harm. Afterwards, open your Apache configuration file or .htaccess file of your website and try to search for section <IfModule mod_headers.c> inside of it. Change it to

<IfModule mod_headers.c>
  # ... YOUR existing stuff ...
  # ========= ========

  # Define which type and which locations of ressources are allowed to be used.
  Header set Content-Security-Policy "default-src 'self';"

  # Preventing your website to be loaded inside of a frame, which is used to perform some attacks (e.g. Clickjacking)
  Header append X-Frame-Options SAMEORIGIN

  # X-XSS-Protection is a feature of Internet Explorer and Webkit that stops pages from loading
  # when they detect reflected cross-site scripting (XSS) attacks.
  Header set X-XSS-Protection "1; mode=block"

  # Do not change the MIME type, just follow.
  Header set X-Content-Type-Options nosniff

  # Enforce HTTPS. Keep the setting for 1 year including all domains and indicate, that it can be added to the HSTS service
  Header set Strict-Transport-Security "max-age=31536000;includeSubDomains; preload"

  # Making cooking inaccessible for JavaScript.
  # Enforcing the transmitting over HTTPS.
  Header always edit Set-Cookie (.*) "$1; HttpOnly; Secure; SameSite=strict"

For most of the item, we use Header set, which means that any existing values will be replaced. Whereas Header edit will transform the information and Header append will append the information (see Apache documentation)

If you add the security to an existing web server, shared server or if you use CMS like WordPress, you will need to be less restrictive about the CSP. For WordPress, you may end up in something like this:

Header set Content-Security-Policy "default-src 'none'; script-src 'unsafe-inline' 'unsafe-eval' 'self'; style-src 'unsafe-inline' 'self'; font-src 'self' data:; object-src 'none'; frame-src 'self'; worker-src 'none';img-src 'self' data: blob: https://*; frame-ancestors 'self'; base-uri 'self'; form-action 'self'; connect-src 'self'"

This would allow you to use Gist and Google Fonts.

After completing the setup, you should use the online check tools from Mozilla to see your configuration and got additional hints. Click here to get there.

Further Readings