blog/_posts/2017-11-14-hardening-apache...

232 lines
8.6 KiB
Markdown

---
title: "Hardening Apache, all in one place"
date: 2017-11-14
last_modified_at: 2022-09-04
url: hardening-apache-all-in-one-place
layout: post
category: Security
image: /img/blog/hardening-apache-all-in-one-place.png
description: "An unified guide to secure Apache web server"
---
[![A missing blog post image](/img/blog/hardening-apache-all-in-one-place.png)](/img/blog/hardening-apache-all-in-one-place.png)
Oops, I did it again ! I should have said "httpd" of course, the famous _Apache web server_.
### Introduction
I was so bored of starting from scratch for each new _VHOST_ created, so the idea of writing an article keeping a template with the best security measures (taken from many places, see [Sources](#sources) below) has come up.
And here we are, a brand new _Markdown_ post about it ! :tada:
Let's start with the first part !
### Part 1 - Securing Apache
If you have never secured _Apache_ globally, you should start with this part (although, if you do, skip it and go to the [second part](#part-2-vhost-specific-configuration)) !
In a few words, the configuration below will... :
* Block all requests (your _VHOSTs_ will have to allow them explicitly on their side)
* Turn off _Apache_ verbosity
* Block all requests to a hidden resource (handful for `.git/` folder for instance)
* Enforce [_OWASP_ headers recommendations](https://www.owasp.org/index.php/Security_Headers)
* Authorize Cookies only on secured connections
* Reduce the default timeout for sessions and limit requests size to 1 MB (you can increase it if you need to)
* Force clients to negotiate only with secure ciphers, on TLS v1.2 (see [Sources](#sources))
Just create this file :
`# nano /etc/apache2/conf.d/security.local.conf`
... and paste the following :
{% highlight apache %}
<Directory />
AllowOverride None
Require all denied
</Directory>
ServerTokens Prod
ServerSignature Off
TraceEnable Off
FileETag None
RedirectMatch 404 "^.*\/\.(?!well-known).*$"
Header always set Referrer-Policy: "same-origin"
Header always set X-Content-Type-Options: "nosniff"
Header always set X-XSS-Protection: "0"
Header always set X-Frame-Options: "SAMEORIGIN"
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self'; frame-ancestors 'self'"
Header always edit Set-Cookie "^(.*)$" "$1;HttpOnly;Secure"
TimeOut 60
LimitRequestBody 1024000
SSLHonorCipherOrder On
SSLProtocol -ALL +TLSv1.2
SSLCipherSuite EECDH+CHACHA20:EECDH+AESGCM
SSLUseStapling On
SSLStaplingCache "shmcb:logs/stapling-cache(150000)"
# For Apache >= 2.4.3
SSLCompression Off
# For Apache >= 2.4.11
SSLSessionTickets Off
BrowserMatch "MSIE [2-6]" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0
BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
{% endhighlight %}
You'll need some new modules to enforce these measures (and those during the second part) :
`# a2enmod headers rewrite ssl`
> I'd advise you to catch a glimpse of the modules already loaded with :
> `# apachectl -M`
> You can easily remove some of them you won't use, as below :
> `# a2dismod cgi autoindex <...>`
**If you need any protection from _DDoS_ or _BruteForce_ attacks, I advise you to follow [this tutorial](https://www.tecmint.com/protect-apache-using-mod_security-and-mod_evasive-on-rhel-centos-fedora/2/).**
Reload _Apache_ to parse and apply the new configuration :
`# systemctl reload apache2.service`
**Now**, you're all set for the second part :wink:
### Part 2 - VHOST specific configuration
Below, you'll find two configurations :
1. The first one is supposed to be named **000-default.conf** : It will listen to the port 80, and redirect to each HTTPS _VHOST_ in function of the domain name requested (just complete it with as many `RewriteCond` as you need)
2. The second one is the content you'll have to duplicate for each of your _VHOST_. They will listen to the port 443 (let's say with [Let's Encrypt](https://certbot.eff.org/) support).
{% highlight apache %}
<VirtualHost *:80>
ServerName your.domain.name
ServerAlias www.your.domain.name
ServerAdmin webmaster@your.domain.name
LogLevel warn
ErrorLog ${APACHE_LOG_DIR}/000-default_error.log
CustomLog ${APACHE_LOG_DIR}/000-default_access.log combined
RewriteEngine On
RewriteCond %{HTTP_HOST} ^your.domain.name$ [OR]
RewriteCond %{HTTP_HOST} ^www.your.domain.name$
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
</VirtualHost>
{% endhighlight %}
---
{% highlight apache %}
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName your.domain.name
ServerAlias www.your.domain.name
ServerAdmin webmaster@your.domain.name
DocumentRoot /path/to/webroot/
<Directory /path/to/webroot/>
Options -Indexes -FollowSymLinks -Includes -ExecCGI
AllowOverride None
Require all granted
</Directory>
Header always set Strict-Transport-Security: "max-age=63072000; includeSubDomains; preload"
RewriteEngine On
RewriteCond %{THE_REQUEST} !HTTP/1\.1$
RewriteRule .* - [F]
SSLEngine On
SSLCertificateFile /etc/letsencrypt/live/your.domain.name/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/your.domain.name/privkey.pem
LogLevel warn
ErrorLog ${APACHE_LOG_DIR}/your.domain.name_error.log
CustomLog ${APACHE_LOG_DIR}/your.domain.name_access.log combined
</VirtualHost>
</IfModule>
{% endhighlight %}
This _VHOST_ needs some explanations :
* Set the webroot and harden the website authorization
* Set HSTS header (see [Sources](#sources))
* Disable (only) HTTP 1.0 requests
* Loads _Let's Encrypt_ SSL certificate
> [We should say "TLS"](https://www.tictech.info/post/ssl_est_mort), shouldn't we ? (Coucou Nico' :wave:)
* Set dedicated logs (useful to debug and monitor which website is under attack)
> Don't forget to enable each one of your websites with :
> `# a2ensite <website>`
#### Note
You may encounter a side effect of your _VHOST_ naming.
Try to access your web server directly with its IP, instead of one of the _VHOST_'s domain names) : <http://your.server.address.ip/>.
It's very likely that you don't want this website to answer when crawlers will start dealing with your server.
To recover from this behavior, just rename the _VHOST_ you want to answer by default to something like `001-your-domain-name.conf`.
When your IP will be accessed on the port 443, _Apache_ will just redirect the query to **the first _VHOST_ name in a "top-down" way**.
### Last words
If you want to use a development _Framework_, it will surely shipped with a `.htaccess` file. Don't forget to pass the `AllowOverride` to `All` to authorize your default settings to be overridden for a specific _VHOST_.
On the same idea, some of them (hello _CakePHP_ :wave:) use symbolic link to enable their plugins. So, you may need to activate `FollowSymLinks` too...
It's good to secure your web server, but if you are hosting a _PHP_ application for instance, it won't block any attack occurring at the "application level"...
---
So this is the end, I hope it helped you :+1:
Please do propose some changes if you think there is something bad (or something missing) ; I'll try to keep this article up-to-date in the future ! :ok_hand:
### Sources
* [HSTS Preloading](https://hstspreload.org/) (by the Chromium project)
* [13 Apache Web Server Security Tips](https://www.tecmint.com/apache-security-tips/)
* [Apache Web Server Hardening & Security Guide](https://geekflare.com/apache-web-server-hardening-security/)
* Securing Apache on Ubuntu ([Part 1](https://www.maketecheasier.com/securing-apache-ubuntu/) & [Part 2](https://www.maketecheasier.com/securing-apache-ubuntu-2/))
* [CryptCheck](https://cryptcheck.fr/)
* [Safeciphers.org](https://safeciphers.org/)
### History of revisions
2022-09-04 - Drop support for Apache < 2.4 and replace `_default_` by `*`
2022-01-27 - Disable legacy XSS filtering through `X-XSS-Protection` header
2020-03-16 - Due to [this notice](https://raymii.org/s/blog/Cancellation_notice_for_cipherlist_ssldecoder_and_certificatemonitor.html), `cipherli.st` has been replaced by `safeciphers.org`
2019-11-16 - `always` set/edit security headers
2018-11-24 - Grants access to special (not-hidden) `/.well-known/` paths
2018-11-11 - Gets rid of _CBC_ encryption mode in ciphers list
2018-10-12 - Adds a default `Referrer-Policy` header to the local security configuration
2018-08-01 - Replaces `Order`, `Allow` and `Deny` options by `Require` for Apache >= 2.4, in a BC way for previous versions
2018-01-14 - Fixes wrong HSTS header setting
2018-01-09 - Adds _Content Security Policy_ header to `security.local.conf`
2017-11-21 - Adds _SSLStapling_ and _Internet Explorer_ specific directives