Server Limits for Apache Security

In this fourth part of a six-part series on Apache installation and configuration, you will learn how to set server configuration limits, prevent information leaks, and more. This article is excerpted from chapter two of Apache Security, written by Ivan Ristic (O’Reilly; ISBN: 0596007248). Copyright © 2006 O’Reilly Media, Inc. All rights reserved. Used with permission from the publisher. Available from booksellers or direct from O’Reilly Media.

Setting Server Configuration Limits

Though you are not likely to fine-tune the server during installation, you must be aware of the existence of server limits and the way they are configured. Incorrectly configured limits make a web server an easy target for attacks (see Chapter 5). The following configuration directives all show default Apache configuration values and define how long the server will wait for a slow client:

  # wait up to 300 seconds for slow clients
  TimeOut 300
  # allow connections to be reused between requests
  KeepAlive On
  # allow a maximum of 100 requests per connection
  MaxKeepAliveRequests 100
  # wait up to 15 seconds for the next
  # request on an open connection
  KeepAliveTimeout 15

The default value for the connection timeout (300 seconds) is too high. You can safely reduce it below 60 seconds and increase your tolerance against denial of ser vice (DoS) attacks (see Chapter 5).

The following directives impose limits on various aspects of an HTTP request:

  # impose no limits on the request bod y
  LimitRequestBody 0
  # allow up to 100 headers in a request
  LimitRequestFields 100
  # each header may be up to 8190 bytes long
  LimitRequestFieldsize 8190
  # the first line of the request can be
  # up to 8190 bytes long
  LimitRequestLine 8190
  # limit the XML request body to 1 million bytes(Apache 2.x only)
  LimitXMLRequestBody 1000000

LimitXMLRequestBody is an Apache 2 directive and is used by the mod_dav module to limit the size of its command requests (which are XML-based).

Seeing that the maximal size of the request body is unlimited by default (2 GB in practice), you may wish to specify a more sensible value for LimitRequestBody . You can go as low as 64 KB if you do not plan to support file uploads in the installation.

The following directives control how server instances are created and destroyed in Apache 1 and sometimes in Apache 2 (as described further in the following text):

  # keep 5 servers ready to handle requests
  MinSpareServers 5
  # do not keep more than 10 servers idle
  MaxSpareServers 10
  # start with 5 servers
  StartServers 5
  # allow a max of 150 clients at any given time
  MaxClients 150
  # allow unlimited requests per server
  MaxRequestsPerChild 0

You may want to lower the maximal number of clients ( MaxClients ) if your server does not have enough memory to handle 150 Apache instances at one time.

You should make a habit of putting a limit on the maximal number of requests served by one server instance, which is unlimited by default in Apache 1 (as indi cated by the 0 MaxRequestsPerChild value) but set to 10000 in Apache 2. When a server instance reaches the limit, it will be shut down and replaced with a fresh copy. A high value such as 1000 (or even more) will not affect web server operation but will help if an Apache module has a memory leak. Interestingly, when the Keep-Alive feature (which allows many requests to be performed over a single network connection) is used, all requests performed over a single Keep-Alive connection will be counted as one for the purposes of MaxRequestsPerChild handling.

Apache 2 introduces the concept of multiprocessing modules (MPMs), which are special-purpose modules that determine how request processing is organized. Only one MPM can be active at any one time. MPMs were introduced to allow processing to be optimized for each operating system individually. The Apache 1 processing model (multiple processes, no threads, each process handling one request at one time) is called prefork, and it is the default processing model in Apache 2 running on Unix platforms. On Windows, Apache always runs as a single process with multiple execution threads, and the MPM for that is known as winnt. On Unix systems running Apache 2, it is possible to use the worker MPM, which is a hybrid, as it supports many processes each with many threads. For the worker MPM, the configuration is similar to the following (refer to the documentation for the complete description):

  # the maximum number of processe s
  ServerLimit 16
  # how many processes to start with
  StartServers 2
  # how many threads per process to create
  ThreadsPerChild 25
  # minimum spare threads across all processes
  MinSpareThreads 25
  # maximum spare threads across all processes
  MaxSpareThreads 75
  # maximum clients at any given time
  MaxClients 150

Since the number of threads per process is fixed, the Apache worker MPM will change the number of active processes to obey the minimum and maximum spare threads configured. Unlike with the prefork MPM, the MaxClients directive now con trols the maximum number of active threads at any given time.

{mospagebreak title=Preventing Information Leaks}

By default, Apache provides several bits of information to anyone interested. Any information obtained by attackers helps them build a better view of the system and makes it easier for them to break into the system.

For example, the installation process automatically puts the email address of the user compiling Apache (or, rather, the email address it thinks is the correct email address) into the configuration file. This reveals the account to the public, which is undesirable. The following directive replaces the Apache-generated email address with a generic address:


By default, the email address defined with this directive appears on server-generated pages. Since this is probably not what you want, you can turn off this feature completely via the following directive:

  ServerSignature Off

The HTTP protocol defines a response header field Server , whose purpose is to identify the software responding to the request. By default, Apache populates this header with its name, version number, and names and version numbers of all its modules willing to identify themselves. You can see what this looks like by sending a test request to the newly installed server:

  $ telnet localhost 80
  Connected to localhost.
  Escape character is ‘^]’.
  HEAD / HTTP/1.0

  HTTP/1.1 200 OK
  Date: Fri, 19 Mar 2004 22:05:35 GMT
  Server: Apache/1.3.29 (Unix)
  Content-Location: index.html.en
  Vary: negotiate,accept-language,accept-charset
  TCN: choice
  Last-Modified: Fri, 04 May 2001 00:00:38 GMT
  ETag: "4002c7-5b0-3af1f126;405a21d7"
  Accept-Ranges: bytes
  Content-Length: 1456
  Connection: close
  Content-Type: text/html
  Content-Language: en
  Expires: Fri, 19 Mar 2004 22:05:35 GMT

This header field reveals specific and valuable information to the attacker. You can’t hide it completely (this is not entirely true, as you will find in the next section), but you can tell Apache to disclose only the name of the server (“Apache”).

  ServerTokens ProductOnly

We turned off the directory indexing feature earlier when we set the Options direc tive to have the value None . Having the feature off by default is a good approach. You can enable it later on a per-directory basis:

  <Directory /var/www/htdocs/download >
      Options +Indexes

Automatic directory indexes are dangerous because programmers frequently create folders that have no default indexes. When that happens, Apache tries to be helpful and lists the contents of the folder, often showing the names of files that are publicly available (because of an error) but should not be seen by anyone, such as the following:

  1. Files (usually archives) stored on the web server but not properly protected (e.g., with a password) because users thought the files could not be seen and thus were secure
  2. Files that were uploaded “just for a second” but were never deleted
  3. Source code backup files automatically created by text editors and uploaded to the production server by mistake
  4. Backup files created as a result of direct modification of files on the production server

To fight the problem of unintentional file disclosure, you should turn off automatic indexing (as described in the “AllowOverride directive” section) and instruct Apache to reject all requests for files matching a series of regular expressions given below. Similar configuration code exists in the default httpd.conf file to deny access to . htaccess files (the per-directory configuration files I mentioned earlier). The follow ing extends the regular expression to look for various file extensions that should normally not be present on the web server:

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

The FilesMatch directive only looks at the last part of the full filename (the basename), and thus, FilesMatch configuration specifications do not apply to directory names. To completely restrict access to a particular directory, for example to deny access to CVS administrative files (frequently found on web sites), use something like:

  <DirectoryMatch /CVS/>
      Order Allow,Deny
      Deny from all

{mospagebreak title=Changing Web Server Identity}

One of the principles of web server hardening is hiding as much information from the public as possible. By extending the same logic, hiding the identity of the web server makes perfect sense. This subject has caused much controversy. Discussions usually start because Apache does not provide facilities to control all of the content provided in the Server header field, and some poor soul tries to influence Apache developers to add it. Because no clear technical reasons support either opinion, discussions continue.

I have mentioned the risks of providing server information in the Server response header field defined in the HTTP standard, so a first step in our effort to avoid this will be to fake its contents. As you will see later, this is often not straightforward, but it can be done. Suppose we try to be funny and replace our standard response “Apache/1.3.30 (Unix)” with “Microsoft-IIS/5.0” (it makes no difference to us that Internet Information Server has a worse security record than Apache; our goal is to hide who we are). An attacker sees this but sees no trace of Active Server Pages (ASP) on the server, and that makes him suspicious. He decides to employ operating system fingerprinting. This technique uses the variations in the implementations of the TCP/IP protocol to figure out which operating system is behind an IP address. This functionality comes with the popular network scanner NMAP. Running NMAP against a Linux server will sometimes reveal that the server is not running Windows. Microsoft IIS running on a Linux server—not likely!

There are also differences in the implementations of the HTTP protocol supplied by different web servers. HTTP fingerprinting exploits these differences to determine the make of the web server. The differences exist for the following reasons:

  1. Standards do not define every aspect of protocols. Some parts of the standard are merely recommendations, and some parts are often intentionally left vague because no one at the time knew how to solve a particular problem so it was left to resolve itself.
  2. Standards sometimes do not define trivial things.
  3. Developers often do not follow standards closely, and even when they do, they make mistakes.

The most frequently used example of web server behavior that may allow exploitation is certainly the way Apache treats URL encoded forward slash characters. Try this:

  1. Open a browser window, and type in the address (two forward slashes at the end). You will get the home page of the site.
  2. Replace the forward slash at the end with %2f (the same character but URL-encoded): The web server will now respond with a 404 (Not Found) response code!

This happens only if the site runs Apache. In two steps you have determined the make of the web server without looking at the Server header field. Automating this check is easy.

This behavior was so widely and frequently discussed that it led Apache developers to introduce a directive ( AllowEncodedSlashes ) to the 2.x branch to toggle how Apache behaves. This will not help us much in our continuing quest to fully control the content provided in the Server header field. There is no point in continuing to fight for this. In theory, the only way to hide the identity of the server is to put a reverse proxy (see Chapter 9) in front and instruct it to alter the order of header fields in the response, alter their content, and generally do everything possible to hide the server behind it. Even if someone succeeds at this, this piece of software will be so unique that the attacker will identify the reverse proxy successfully, which is as dangerous as what we have been trying to hide all along.

Not everything is lost, however. You may not be able to transform your installation’s identity, but you can pretend to be, say, a different version of the same web server. Or you can pretend to be a web server with a list of modules different from reality. There is a great opportunity here to mislead the attacker and make him spend a lot of time on the wrong track and, hopefully, give up. To conclude:

  1. With a different server name in the Server header field, you can deflect some automated tools that use this information to find servers of certain make.
  2. It is possible to fool and confuse a range of attackers with not quite developed skills. Not everyone knows of TCP/IP and HTTP fingerprinting, for example. 
  3. Small changes can be the most effective.

Now, let’s see how we can hide server information in practice.

{mospagebreak title=Changing the Server Header Field}

The following sections discuss alternative approaches to changing the web server identity.

Changing the name in the source code

You can make modifications to change the web server identity in two places in the source code. One is in the include file httpd.h in Apache 1 (ap_release.h in Apache 2) where the version macros are defined:

  #define SERVER_BASEVENDOR   "Apache Group "
  #define SERVER_BASEPRODUCT  "Apache"
  #define SERVER_BASEREVISION "1.3.29"

Apache Benchmark recommends that only the value of the SERVER_BASEPRODUCT macro be changed, allowing the other information such as the version number to remain in the code so it can be used later, for example, for web server version identi fication (by way of code audit, not from the outside). If you decide to follow this recommendation, the ServerTokens directive must be set to ProductOnly , as discussed earlier in this chapter.

The reason Apache Benchmark recommends changing just one macro is because some modules (such as mod_ssl) are made to work only with a specific version of the Apache web server. To ensure correct operation, these modules check the Apache version number (contained in the SERVER_BASEVERSION macro) and refuse to run if the version number is different from what is expected.

A different approach for changing the name in a source file is to replace the ap_set_version() function, which is responsible for construction of the server name in the first place. For Apache 1, replace the existing function (in http_main.c) with one like the following, specifying whatever server name you wish:

  static void ap_set_version(void)
/* set the server name */
/* do not allow other modules to add to it */

For Apache 2, replace the function (defined in core.c):

  static void ap_set_version(apr_pool_t *pconf)
/* set the server name */
ap_add_version_component(pconf, "Microsoft-IIS/5.0");
/* do not allow other modules to add to it */

Changing the name using mod_security

Changing the source code can be tiresome, especially if it is done repeatedly. A different approach to changing the name of the server is to use a third-party module, mod_security (described in detail in Chapter 12). For this approach to work, we must allow Apache to reveal its full identity, and then instruct mod_security to change the identity to something else. The following directives can be added to Apache configuration:

  # Reveal full identity (standard Apache directive )
  ServerTokens Full
  # Replace the server name (mod_security directive)
  SecServerSignature "Microsoft-IIS/5.0"

Apache modules are not allowed to change the name of the server completely, but mod_security works by finding where the name is kept in memory and overwriting the text directly. The ServerTokens directive must be set to Full to ensure the web server allocates a large enough space for the name, giving mod_security enough space to make its changes later.

Changing the name using mod_headers with Apache 2

The mod_headers module is improved in Apache 2 and can change response headers. In spite of that, you cannot use it to change the two crucial response headers, Server and Date. But the approach does work when the web server is working in a reverse proxy mode. In that case, you can use the following configuration:

  Header set Server "Microsoft-IIS/5.0"

However, there is one serious problem with this. Though the identity change works in normal conditions, mod_headers is not executed in exceptional circumstances. So, for example, if you make an invalid request to the reverse proxy and force it to respond with status code 400 (“Bad request”), the response will include the Server header containing the true identity of the reverse proxy server.

Please check back next week for the continuation of this article.

Google+ Comments

Google+ Comments