232 lines
8.6 KiB
Markdown
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
|