Anatomy of a hardened Apache2 configuration
Some Suggestions
This guide applies to Apache 2.4+.
I cover most things here, but anything else is easily found at the Apache2 documentation site.
So first I want to suggest that you break up your configuration files, and then include each site (and other major config types) into the main server config.
Your configuration file with server wide settings will be called
, or sometimes 1
apache2.conf
and is usually going to be located in the1
httpd.conf
directory. Under this main apache2 configuration directory, you will probably also see some other directories, and these are going to be
included from your primary configuration file later. The three we will be using today will be 1
/etc/apache2/
/ 1
mods-available
, 1
mods-enabled
/
1
sites-available
, and 1
sites-enabled
/ 1
conf-available
. Now you can really organize all this however you want, so long as you include everything correctly.
But I suggest using the default scheme, as most people, as well as documentation, follows this setup.1
conf-enabled
The Primary Config File
Now that that is out of the way, we’re going to take a look at the current config, if you have just installed apache2 from your package manager, it is going to look very generic, like this (except with a lot of documentation commented out, I will be omitting):
Hint: You can document your own configuration as you like by adding a hash “
” character in front of what you want to remind yourself or someone
else!1
#
Most of these things should be left in, and can be unchanged.
So the first line
just tells us what directory all our configuration things will be housed in. It should never have a trailing
slash.1
ServerRoot "/etc/apache2"
Our first security type feature is the
and 1
User
declerations, which tell the apache2 binary what priveleges to run under. This is important
because if the server does happen to get pwnt, then the attacker does not get higher privs than what are listed here.1
Group
Warning: NEVER set either of these to root or your own personal account user.
Your next two important security type directives are ErrorLog, and LogLevel. I would recommend leaving these the same, except if you are having issues you are welcome to change the log level to anything from trace1 to trace8, as well as debug, info, notice, warn, error, crit, alert, emerg. This will give you some debugging output. Be careful not to leave the debugging output on in production, this will probably cause performance issues under load.
Your next three important things are your single
files and your 1
Include
directories, each with files to include in their first level.
These will be important later on.1
IncludeOptional
Now the only
directive that I leave in my prod servers is:1
Directory
So that in no way can the root directory of our server be accessed. We first tell it to follow every simlink under, and then explicityly disallow reading of this directory by anything client side, and allows no possiblity of .htaccess override.
We also then completely disallow client side loading of any file beginning with .ht. This is a reference to
and 1
.htaccess
, in case those
are anywhere that are currently being served, and in the case of 1
.htpasswd
, it will be.1
.htaccess
You’ll also have your LogFormat directives that tell the server how to generate your
and 1
error.log
. Unless otherwise specified, these will
appear in 1
access.log
.1
/var/log/apache2/
Now Some Security Focused Additions
I’ll share a somewhat redacted version of one of my own
files. Some these things may need tweaking for your intended use case, please
don’t just copy/paste it.1
apache2.conf
Note: You can add the next few things I talk about to
, or keep them all in one place if you would like!1
/etc/apache2/conf-enabled/security.conf
So lots of this is the same with some minor modifications, but I’ll go over things you should consider adding.
First, in case of unexpected errors, you should include your email in the server config so a user can contact you in case of a service outage.
We do this with the
server environment variable.1
SetEnv SERVER_ADMIN
We shoudl also turn on inline header addition and modification for the next couple lines, we’ll do this with
. As a result now we can set things like server-side XSS protection with:
1
LoadModule headers_module modules/mod_headers.so
and it’s companion options: 1
Header always set X-XSS-Protection "1; mode=block"
and
1
Header always append X-Frame-Options deny
. We do this via headers because some of this needs to direct our clients, the web browsers, how to
interact wtih some of the data we share with them.1
Header always set X-Content-Type-Options "nosniff"
Another thing we can accomplish with header addition is using our CSP, or Content Security Policy, basically directing via the server what the client
browser can pull and use on the page from an external source, and where specifically they can pull it from. We do this with
. If I say wanted to be able to run externally hosted javascript from js.google.com or script.google.com, we
could set it as such: 1
Header always set Content-Security-Policy
. As you can see, there are different types, for
javascript, iframes, css, etc.1
Header always set Content-Security-Policy "script-src 'self' *.google.com;"
We can also set our Referrer-Policy header, which is important in the case of other insecure websites picking up which page our clients were on last.
For my uses, I have set mine to
, but you can also set to a number of others including: “no-referrer”,
“no-referrer-when-downgrade”, “same-origin”, “origin”, “strict-origin”, “origin-when-cross-origin”, “strict-origin-when-cross-origin”, and
“unsafe-url”. Each has it’s own pace, and you can read more about each policy specifically here.1
no-referrer-when-downgrade
Our
header also should be set on most modern webservers. This dictates what rights our server has to access on the client browser’s
computer, like a camera, or their fine location. Your site and what you use the browser for is going to tell you what permissions you need, so here I will
deferr to a nice Permissions Policy Generator I’ve found useful that can automagically generate this
string for you without errors. I suggest only asking for what you really need, as asking for too many “unused” permissions is a great way to turn a
user away.1
Permissions-Policy
One cool thing we can do with the
directive is do things like edit a cookie inline before sending it to the user, so say, we want to bump
all cookies to 1
Header edit
we would use the regular expression: 1
Httponly;Secure;
as a catchall.1
Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure;
I normally also remove access to insecure SSL protocols when connecting to my server. There is nothing worse than thinking your connection is
secure, when it is not. You can do this by using the SSLProtocol directive and setting it as you wish. I set mine:
for good measure.1
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
If you would like to restrict access to a specific directory to only the user “marshall”, you can do so by creating a password file with htpasswd, ex:
, and then adding a section to your config file that looks something like this:1
htpasswd -c /etc/apache2/htpasswd.sec marshall
If you would like to add another user the ability to access that directory, you could create their access token with htpasswd, and then simply add their
username to the line
. If instead you would like to restrict access to an IP address, you could use the line
1
Requre user marshall [here]
, or specificy their hostname with 1
Require ip 123.123.123.123
. To negate the access, add the keyword not between Require
and ip/host/user.1
Require host oxagast.org
It is important to make sure our now secured server does not leak internal server information when an attacker is poking at it, generating error codes.
So now that our server is tightened up, we should set
, 1
TraceEnable Off
and finally 1
ServerSignature Off
. Now our errors should be
able to be read, and seen as an error by an end user, but won’t leak important serverside information like IP addresses and server versions. For future
reference, trace should always be disabled on an internet facing production server, as it is an unsafe HTTP method.1
ServerTokens Prod
The Site
Now we can head over to
and create your site. I’ll assume you already have SSL/HTTPS setup and working for your site,
where it be with LetsEncrypt, or something else. I’ll also assume you have a working site with at least a main page and a subdirectory with something in
it.1
/etc/apache2/sites-available
I’ll show you a simple config of one of my sites with some more sensitive things removed.
So in
I have the following file called 1
/etc/apache2/sites-available
. There should also a symbolic link that links this file to
1
site.com-ssl.conf
so that the data is parsed by then served by apache2.1
/etc/apache2/sites-enabled
So as you can see, a rather generic apache2 setup with a couple additions.
You will need a
at minimum pointing to the lowest directory you would like to serve for this site.1
DocumentRoot
Our Directory tags point to a place on the filesystem that we would like to add the enclosed directives to. The Location tags enclose a location that is served by the webserver that we would like to add the directives to. This is an important distinction.
If we are not using CGI (like Perl or PHP) in this directory, make sure to add
to the Options directive. You may also add or omit 1
-ExecCGI
,
with either a plus or minus, to tell it weather we want a directory listing in child directories or not. I leave this off here.1
Indexes
Assuming we have our header modifications on, we can have
for access control, if you are not pulling
from anything else, you can set this to your site only to tighten it up a little bit.1
Header always set Access-Control-Allow-Origin "*"
We want our url rewrite engine on so that we can tell it ONLY to alllow safe HTTP methods with
and then 1
RewriteCond %{REQUEST_METHOD} !^(GET|HEAD|POST|OPTIONS)$ [NC]
, and we would like to only have valid HTTP requests
come through, hence the next directive 1
RewriteRule .? - [F,NS,L]
and 1
RewriteCond %{THE_REQUEST} !^[A-Z]{3,9}\ .+\ HTTP/(0\.9|1\.0|1\.1) [NC]
.1
RewriteRule .? - [F,NS,L]
To wrap it up, we can optionally run a HTTP server as well as our HTTPS server, and just use the HTTP to bump over to HTTPS with a rewrite, so if you
would like to do this, create a file called
that looks something like this:1
site.com.conf
Conclusion
Now you’ll just need to run
to restart the server with your new settings. Now that we have it tightened up, you may have
a little more peace of mind against hackers. However, always make sure to check your logs for suspicious code.1
systemctl restart apache2
Feel free to email me with comments and suggestions!
Happy serving!
If you enjoy my work, sponsor or hire me! I work hard keeping oxasploits running!
Bitcoin Address:
bc1qq7vvwfe7760s3dm8uq28seck465h3tqp3fjq4l
Thank you so much and happy hacking!