in Howto Apache SSL Security ~ read.
Protecting my web server

Protecting my web server

Just recently I finished an article for the Dutch Java magazine about securing your website by means of https connections. In the article, we (Ivo Woltring and I) describe details on how to get a certificate for your Webserver from the LetsEncrypt CA.

The end result of those steps is a site that only allows for https connections. This solved the problem of others listening in on your visitors. Hacking your site is definitely more difficult, but not all possibilities are resolved. XSS, MITM, Clickjacking, CORS, Privacy protection of your visitors (Referer), etc.. are still open.

I start off with a small introduction of various sites that provide information about the security. With just two of them I got tears in my eyes. After some digging around I went from a bad or low classification to the high classifications. In this multi part series I provide you with a description of the steps I took to solve (not all) these issues.

Is my site secure?

On the net you can find quite a lot of offers that let you check the hack-ability of your site; to name a few

This is a combination of free, trial or paid. When you start with these scanners you will get tears in your eyes. Each of these scanners will find security threads on your site. Annoying thing is that not all of them find the same things or rate then equally.

SSL Tests

When starting this article I mentioned the certificates from LetsEncrypt. I installed these and thought I was done with it, well not quite, SSLLabs and Security headers did not look promising:

SSL Labs result summary

Security Headers result summary

I was a bit surprised about the results I got, so just getting a certificate and make sure your site is only available under SSL does not solve all of the problems.

Attacking the problem

For me, this was a new territory! I know about SQL injection and some of the OWASP guidelines (been a while writing frontend apps). This is not about following the OWASP guidelines this is hardcore server configuration and response header manipulation!

Naturally, both sites provided detailed explanations of the issues found on the site but not the easiest descriptions of the solutions to them. Thus is got lost in google space looking for answers. Googling on the header field names will provide you with a lot of documentation and discussion on what they are for and how to configure them. I was a bit mind blown after this. Have I been this ignorant?

Apparently not, this image is taken from a test to an organization that has a high-security standard: Redacted

Ok slightly better than myself, but still not a great rating. And a lot of room to improve my security rating.

Solving the issues

In this part I will describe the steps taken to get to a better rating in these tests. This article describes the simpler additions a made to my Apache configuration. The next article will go into the more advanvanced configuration of my Apache server.

Strict transport security

Sites have always heavily relied on a 301/302 redirect to take users from browsing over HTTP to HTTPS. With browsers defaulting to HTTP when you type in an address like, this has previously been the only way. HSTS allows you to tell a browser that you always want a user to connect using HTTPS instead of HTTP. This means any bookmarks, links or addresses the user types will be forced to use HTTPS, even if they specify HTTP. Read more in my blog on HSTS - The Missing Link In Transport Layer Security and check out HSTS Preloading too. This policy will enforce TLS on your site and all subdomains for a year.

-- Scott Helme

The actual implementation is quite simple, for Apache just add:
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

This will force the user to use the Https connection for a year.


The X-Frame-Options HTTP response header can be used to indicate whether or not a browser should be allowed to render a page in a <frame>, <iframe> or <object>. Sites can use this to avoid clickjacking attacks, by ensuring that their content is not embedded into other sites.

-- Mozilla Developer Network

Yes I definitely do not want others to insert a frame into my site (think about disqus of similar comment platforms)

Apache configuration:
Header always append X-Frame-Options SAMEORIGIN


The HTTP X-XSS-Protection response header is a feature of Internet Explorer, Chrome and Safari that stops pages from loading when they detect reflected cross-site scripting (XSS) attacks. Although these protections are largely unnecessary in modern browsers when sites implement a strong Content-Security-Policy that disables the use of inline JavaScript ('unsafe-inline'), they can still provide protections for users of older web browsers that don't yet support CSP.

-- Mozilla Developer Network

Apache configuration:
Header always set X-XSS-Protection "1; mode=block"


The X-Content-Type-Options response HTTP header is a marker used by the server to indicate that the MIME types advertised in the Content-Type headers should not be changed and be followed. This allows to opt-out of MIME type sniffing, or, in other words, it is a way to say that the webmasters knew what they were doing.

-- Mozilla Developer Network

The best part of this quote is: "the webmasters knew what they were doing", so go for it.

Apache configuration:
Header always set X-Content-Type-Options "nosniff"

Do not provide system information

The last simple thing to configure is the hiding of the information about your server. Giving away to much information about the server you are running is handing possible hacks on a platter to others.

for example the average Apache server send a response with the following informtion:

Date    Wed, 14 Oct 2009 05:59:59 GMT  
Server    Apache/2.2.3 (CentOS) PHP/5.2.9 mod_ssl/2.2.3 OpenSSL/0.9.8b  
X-Powered-By    PHP/5.2.9  
X-Pingback    .....  
Expires    Wed, 11 Jan 1984 05:00:00 GMT  
Last-Modified    Wed, 14 Oct 2009 06:00:00 GMT  
Cache-Control    no-cache, must-revalidate, max-age=0  
Pragma    no-cache  
Vary    Accept-Encoding,User-Agent  
Content-Encoding    gzip  
Content-Length    10636  
Keep-Alive    timeout=2, max=100  
Connection    Keep-Alive  
Content-Type    text/html; charset=UTF-8`  

To make sure you do not tell too much about your server add the following header:
Header always unset "X-Powered-By"

This disables the PHP engine or other engines. I choose to unset this in the header.
An alternative is to change your php.ini
expose_php = Off

Next is removing the details of your apache server. This needs to be done by means of directives.

ServerTokens Prod ServerSignature Off

To be continued

The hardening described above are just the simple parts. But you are not there yet. In the next post, I will go into the Nitty gritty of the SSL hardening and content security header.