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
- https://www.ssllabs.com/ssltest/index.html
- https://securityheaders.io/
- https://detectify.com/
- https://www.scanmyserver.com/
- https://sucuri.net/
- http://www.quttera.com/
- https://www.acunetix.com/vulnerability-scanner/register-online-vulnerability-scanner/
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:
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:
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 scotthelme.co.uk, 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.
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.
X-Frame-Options
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.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
X-XSS-Protection
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.
Apache configuration:
Header always set X-XSS-Protection "1; mode=block"
X-Content-Type-Options
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.
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.