Apache - Lockdown

[Ref: Security Tips, Apache Security ]

As your Apache server is standing out in the wilderness, it's always a good idea to review what you can do to secure your installation.

Do not take these notes as a fair and complete treatise on this subject. I'm placing notes here as a reference for myself, to follow with my website deployments.

Read Up from people who actually have a clue about this stuff, try the O'Reilly Book and others.

The Australian Defence Signals Directorate has a good list of things you need to do to lock-down, protect your environment. We'll pretend that you're already addressing issues like:

  • Patching your system to the latest stable release,
  • restricting administrator privileges,
  • defence-in-depth,
  • disable unnecessary features
  • storing backups, etc.

File Permissions

Security Tips tell's us what needs to be set as file and directory permissions.

The reminder for me, is when you host virtualhosts (and the way I do it) is to make sure that files accessible to users (e.g. log files) are read-only for everyone other than the server.

Configuration

Since we have full management of our websites, we choose to not support site configurations using .htaccess files and require the appropriate configuration into the Apache server configuration.

The .htaccess file is defined as the AccessFileName with the below directive:

AccessFileName .htaccess

The OpenBSD configuration disables .htaccess through the default configuration shown below:

<Directory />
    Options FollowSymlinks
    AllowOverride None
</Directory>

If you change the above settings, then make sure you follow through the requirements for securing your pages.

AllowOverride directive
Syntax: AllowOverride All|None|directive-type [directive-type] ...
Default: AllowOverride All

When this directive is set to None, then .htaccess files are completely ignored. 
In this case, the server will not even attempt to read .htaccess files in the filesystem.

When this directive is set to All, then any directive which has the .htaccess 
Context is allowed in .htaccess files.

There are also some performance benefits to not using .htaccess files for those who can get away with not supporting them.

The OpenBSD default configuration already restricts access to the .htaccess file from clients:

<Files .htaccess>
    Order allow,deny
    Deny from all
</Files>

If you install a web framework/cms that requires use of .htaccess, and you're not willing to manually insert them into the configuration file, you can explicitly enable .htaccess for that installation path.

Authentication

[Ref: Authentication, Authorization, and Access Control, How to Password Protect a Directory on Your Website ]

To manage access through authenting a client, two things are required to password protect.

  • Authentication Directives
  • Create the password file

Authentication Directives

In your Apache Configuration file, the section related to your web path, put something like the below.

AuthName "Text to show in the Dialog Prompt"
AuthType Basic
AuthUserFile /var/www/conf/auth/siteX
require valid-user

Where the path /var/www/conf/auth/ is our mythical path for storing site specific authentication text files.

The directives are basic, simple to start with. You can choose some more fancy approach if you understand what you are doing.

Password file

[Ref: htpasswd(1), htdigest(1)]

As another mechanism for control, we can specify password authentication for files or paths using, htpasswd(1) or htdigest(1). It is a simplified system for providing some level of protection, but be aware that data is transferred cleartext and you really want to use SSL encryption between your site and users to provide any real level of security.

htpasswd(1)

The password file, from the above sample, is the file /var/www/conf/auth/siteX

Refer to the htpasswd(1) for a more complete description, but the steps will be similar to the below:

$ sudo htpasswd -c /var/www/conf/auth/siteX the-first-user-name

For the 1st execution, you need the "-c"

-c Create the passwordfile.  If passwordfile already exists,
   it is rewritten and truncated.  This option cannot be
   combined with the -n option.

You should have a resulting file similar to the following:

username-1:encrypted-password1
username-2:encrypted-password2
username-3:encrypted-password3

Obviously, subsequent iterations (use of the command) do not use -c or you will blank-out your authentication file.

$ sudo htpasswd /var/www/conf/auth/siteX another-user-name

After you have completed the above for the users you wish to have access, make sure that the file: /var/www/conf/auth/siteX has the appropriate permissions for Apache to load.

htdigest(1)

[Ref: Digest authentication]

Extending the above sample, for a file /var/www/conf/auth/siteX.htdigest

Refer to the htdigest(1) for a more complete description, but the steps will be similar to the below:

$ sudo htdigest -c /var/www/conf/auth/siteX REALM the-first-user-name

For the 1st execution, you need the "-c"

-c Create the passwordfile.  If passwordfile already exists,
   it is deleted first.

Obviously, subsequent iterations (use of the command) do not use -c or you will blank-out your authentication file.

$ sudo htdigest /var/www/conf/auth/siteX REALM another-user-name

You should have a resulting file similar to the following:

username-1:REALM:encrypted-password1
username-2:REALM:encrypted-password2
username-3:REALM:encrypted-password3

Note, "REALM" is something you specify at the command-line, and matches the "AuthName" specified in your Apache Configuration.

AuthName "REALM"
AuthType Digest
AuthDigestFile /var/www/conf/auth/siteX.htdigest
require valid-user

After you have completed the above for the users you wish to have access, make sure that the file: /var/www/conf/auth/siteX.htdigest has the appropriate permissions for Apache to load.

Path/Directory Protection

[Ref: Directory, Protect Server Files by Default]

Our base install is a 'chroot' version of Apache, running from /var/www, and serving up documents initially from /var/www/htdocs.

To set a baseline of restrictions, we set the following for all paths not explicitly allowed:

<Directory />
    Options FollowSymlinks
    AllowOverride None
</Directory>
Options directive
Syntax: Options [+|-]option [[+|-]option] ...
FollowSymLinks
The server will follow symbolic links in this directory.

Note: even though the server follows the symlink it does not change the 
pathname used to match against  sections.

Note: this option gets ignored if set inside a  section.

The Apache documentation is stricter on path access,

<Directory />
    Order Deny,Allow
    Deny from all
</Directory>

Look up the documentation, and the O'Reilly book for more discussion.

The knowledge draws further, into blocking directories that are often 'left-behind' and shouldn't be there.

<DirectoryMatch "(/CVS/|^\.git|.*/\.git|^\.svn|.*/\.svn)">
    Order Allow,Deny
    Deny from all
</DirectoryMatch>

File Protection

[Ref: WordPress, Tips & Tricks]

We've demonstrated above, how to lockdown for the file .htaccess

Additional example, for approving files, after locking down a directory.

<Files ~ ".(xml|css|jp?g|png|gif|js)$">
    Order Deny,Allow
   Allow from all
</Directory>

or, in an open system you could like down files that shouldn't be on the system anyway?

<FilesMatch "(^\.ht|~$|\.bak$|\.BAK$)">
    Order Allow,Deny    
    Deny from all
</FilesMatch>

Source/IP Restrictions

We are also able to restrict access by network or host ip-address

For a network,

Order Deny,Allow
Deny from all
Allow from 192.168.14.0/24

To limit access to specific IP Addresses, use the following Allow from line

Allow from 127.0.0.1 192.168.14.45 192.168.14.47

The problem I'm always having with the IP-Address restrictions, is that I often forget that the IP Addresses are separated by a (space), no "," or other delimeter is involved.

Performance

Performance related options in Apache have an impact on the performance and stability of your site. It is good to know some of the Directives and monitor your site for where they maybe appropriate:

Time Out

The TimeOut directive currently defines the amount of time Apache will wait for three things:

1.The total amount of time it takes to receive a GET request.
2.The amount of time between receipt of TCP packets on a POST or PUT request.
3.The amount of time between ACKs on transmissions of TCP packets in responses.

We plan on making these separately configurable at some point down the road. 
The timer used to default to 1200 before 1.2, but has been lowered to 300 which is 
still far more than necessary in most situations. It is not set any lower by default 
because there may still be odd places in the code where the timer is not reset when 
a packet is sent. 

Consider, tune this down if your users are locked out due to the below MaxClients option due to Denial of Service attacks.

Concurrency

The OpenBSD configuration file documents, and provides sane defaults, review these depending on the type of use expected from your server:

  • MaxClients
  • MinSpareServers
  • MaxSpareServers
  • ListenBacklog
MaxClients/ListenBacklog
MaxClients directive

The MaxClients directive sets the limit on the number of simultaneous requests 
that can be supported; not more than this number of child server processes will 
be created.

Any connection attempts over the MaxClients limit will normally be queued, up to a 
number based on the ListenBacklog directive. Once a child process is freed at the 
end of a different request, the connection will then be serviced.

The default configuration in OpenBSD is 150 (as opposed to 256 by Apache).

Consider: 150 seems reasonable for our basic single site, but might effect responsiveness during high load, or when your serving multiple virtual hosts. If your system is capable of dealing with a higher load, your sites may be more responsive, while still stable with a different configuration size.

Syntax: ListenBacklog backlog
Default: ListenBacklog 511

The maximum length of the queue of pending connections. Generally no tuning is 
needed or desired, however on some systems it is desirable to increase this 
when under a TCP SYN flood attack. See the backlog parameter to the listen(2) 
system call.

Consider: Issues described in the manual references another Operating System.

Min/MaxSpareServers
Syntax: MaxSpareServers number
Default: MaxSpareServers 10

The MaxSpareServers directive sets the desired maximum number of idle child 
server processes. An idle process is one which is not handling a request. 
If there are more than MaxSpareServers idle, then the parent process will 
kill off the excess processes.

Tuning of this parameter should only be necessary on very busy sites. Setting 
this parameter to a large number is almost always a bad idea.
Syntax: MinSpareServers number
Default: MinSpareServers 5

The MinSpareServers directive sets the desired minimum number of idle child 
server processes. An idle process is one which is not handling a request. 
If there are fewer than MinSpareServers idle, then the parent process creates 
new children at a maximum rate of 1 per second.

Tuning of this parameter should only be necessary on very busy sites. Setting 
this parameter to a large number is almost always a bad idea.

Note that setting this directive to some value m ensures that you will always have at 
least n + m httpd processes running when you have n active client requests.

Consider: The default minspare/5 and maxspare/10 seems good to my eyes, but an important knob to be aware of.

Large Requests

Syntax: LimitRequestBody bytes
Default: LimitRequestBody 0

specifies the number of bytes from 0 (meaning unlimited) to 2147483647 (2GB) 
that are allowed in a request body.

The LimitRequestBody directive allows the user to set a limit on the allowed 
size of an HTTP request message body within the context in which the directive 
is given (server, per-directory, per-file or per-location). If the client 
request exceeds that limit, the server will return an error response instead 
of servicing the request. The size of a normal request message body will 
vary greatly depending on the nature of the resource and the methods allowed 
on that resource. CGI scripts typically use the message body for passing form 
information to the server. Implementations of the PUT method will require a 
value at least as large as any representation that the server wishes to accept 
for that resource.

Consider:

Specify a reasonable size for the expected maximum RequestBody for your sites. If you are not allowing file uploads, then you obviously do not need unlimited size? The following is a 1MB, which is large enough for most typing/forum posts?

LimitRequestBody 1048576