Access control is a requirement for many websites. This means that certain content or areas of the website are only accessible to clients that come from a particular range of IP addresses or provide a valid username and password, for example. Access control can be implemented at a variety of levels, including at the operating-system level with packet filtering rules and at the web application level with forms, sessions, and cookies. This chapter deals exclusively with implementing access control, authentication, and authorization using the bundled Apache modules. This chapter also explains how different configuration settings can affect the security of your server and details a number of steps that you can take to improve it.
Apache provides a number of modules that allow you to control access to your content. The two main ones are mod_access
, which allows controlling access based on the origin IP address and other characteristics of the request, and mod_auth
, which authenticates users based on a username and password.
There are a number of other modules that will be mentioned in this chapter but will not be covered in detail because they are not used as often.
Apache’s authorization and authentication framework was completely overhauled in Apache 2.2. Although most of the changes have occurred at the source code level, there are a number of user-visible changes. For the sake of clarity and because most of the basic concepts still apply, this chapter will primarily describe Apache 1.3 and 2.0 configuration. The Apache 2.2-specific changes will be discussed in the “Apache 2.2” section, later in the chapter.
You authenticate users of your website for tracking or authorization purposes. The HTTP specification provides two authentication mechanisms: basic and digest. In both cases, the process is the following:
A client tries to access restricted content in the web server.
Apache checks whether the client is providing a username and password. If not, Apache returns an HTTP 401 status code, indicating that user authentication is required.
The client reads the response and prompts the user for the required username and password (usually with a pop-up window).
The client retries accessing the web page, this time transmitting the username and password as part of the HTTP request. The client remembers the username and password and transmits them in later requests to the same site, so the user does not need to retype them for every request.
Apache checks the validity of the credentials and grants or denies access based on the user identity and other access rules.
In basic authentication, the username and password are transmitted in clear text, as part of the HTTP request headers. This poses a security risk because an attacker could easily peek at the conversation between server and browser, learn the username and password, and reuse them freely afterward. Digest authentication provides increased security because it transmits a digest instead of the clear-text password. A digest algorithm is a mathematical operation that takes a text and returns another text, a digest, which uniquely identifies the original one. If a text changes, so does the digest. The digest is based on a combination of several parameters, including the username, password, and request method. The server can calculate the digest on its own and check that the client knows the password, even when the password itself is not transmitted over the network.
Unfortunately, although the specification has been available for quite some time, not all browsers support digest authentication or do it in a compatible manner.
In any case, for both digest and basic authentication, the requested information itself is transmitted unprotected over the network. A better choice to secure access to your website involves using SSL, as explained in Chapter 7.
<Directory /usr/local/apache2/htdocs/private> Order Allow, Deny Allow from 192.168.0 example.com Deny from guest-terminal.example.com </Directory>
The example shows a sample configuration using IP and hostname-based access control with mod_access
. Allow
directives specify which individual IP addresses, networks, and hostnames have access to the content. Deny
directives specify which ones will be denied. The Order
directive specifies how Allow
and Deny
directives are evaluated.
In this example, the Order Allow, Deny
directive specifies that Allow
directives are to be evaluated first and Deny
directives will be evaluated last. The order in which the directives are evaluated is important, and in this case the Deny
directive will take precedence. Also, Order Allow, Deny
ensures that if the client does not match any Allow
directive, it will be denied access by default. Don’t worry if you are a bit confused about how access control works. It is really easy once you understand the way directives are evaluated.
<Directory /usr/local/apache2/htdocs/private> AuthType Basic AuthName "Password Protected Area" AuthUserFile /usr/local/apache2/conf/htusers Require user admin </Directory>
The listing shows a sample configuration snippet that password-protects a directory. AuthType
defines the authentication type: in this case, HTTP basic authentication. AuthName
associates a text with the area that will be password-protected. This text will be presented to the user when the browser prompts her for a password (usually in a separate pop-up window). The AuthUserFile
points to the user database and the Require
directive specifies a user who will be granted access upon successful authentication. The following sections include more details on the previous example as well as instructions on how to create and manipulate the user database and how to combine IP and user-based control access, as shown in the “Combining Access Control Methods” section.
To create a user database (also known as a password file), you can use the htpasswd
utility included with Apache. The syntax to create a new password file and add a user to it on Unix is shown in the example. On Windows, you will need to use
htpasswd.exe -cm file userid
If you want to add a new user to an existing password file, the syntax on Unix is simply
htpasswd file userid
and on Windows
htpasswd.exe -m file userid
You will be asked for a password and it will be added to the user database.
You should not keep the password file in any directory accessible from the Web. You should not use -c
when adding users to an existing file, as this will destroy the previous contents.
As an example, the following line creates a password file named htusers
and adds a user named admin
:
htpasswd -c /usr/local/apache2/conf/htusers admin
<Directory /usr/local/apache2/htdocs/private> AuthType Basic AuthName "Password Protected Area" AuthUserFile /usr/local/apache2/conf/htusers AuthGroupFile /usr/local/apache2/conf/groups Require group administrators </Directory>
You can instruct Apache to allow access to any valid user in the database that successfully authenticates with
Require valid-user
If you need to authorize only a certain group of users, you can explicitly list them in the arguments to Require
:
Require user userid1 userid2
If you have a great number of users, a more convenient way to accomplish this is to use the AuthGroupFile
directive. This directive points to a file containing group information in the following format:
groupname: userid1 userid2 userid3 [..]
For example
administrators: admin boss users: admin boss user1 user2
The example at the beginning of this section shows a configuration snippet that allows access only to those users that successfully authenticate themselves and also belong to the group administrators
. In this example, that would mean users admin
and boss
.
<DirectoryMatch /home/*/public_html> AuthType Basic AuthName "Private Area" AuthDBMUserFile /usr/local/apache2/conf/dbmusers AuthDBMGroupFile /usr/local/apache2/conf/dbmusers AuthDBMAuthoritative on Require group student faculty </DirectoryMatch>
The mod_auth_dbm
module is equivalent in functionality to mod_auth
, but stores user data in a file-based database, speeding data lookup when there is a large number of users. This module provides a number of directives such as AuthDBMAuthoritative
, AuthDBMUserFile
, and AuthDBMGroupFile
, which are equivalent in syntax and functionality to the plain-text ones provided by mod_auth
. To manipulate the user and group files, you will need to use htdbm
and dbmmanage
, the counterparts to mod_auth
’s tools. Note that group and user data can be stored in the same database, as shown here.
Sometimes, it is desirable to restrict access to certain content (such as a company’s internal website) to specific IP addresses, such as those coming from an internal network. This example will allow access to the directory /usr/local/apache2/htdocs/private
and its subdirectories only to clients with IP addresses in the range 192.168.0.1 to 192.168.0.254.
The argument passed to the Directory
container must literally match the filesystem path that Apache uses to access the files.
The line Order Allow, Deny
denies access by default and only clients that match the Allow
directive will be granted access. The Allow
directive can accept multiple individual IP addresses or a certain address range of IP addresses. Check the directive reference for details.
You can also allow access only to specific IP addresses using the same code in a .htaccess
file in /usr/local/apache2/htdocs/private
:
Order Allow,Deny Allow from 192.168.0
<Directory /usr/local/apache2/htdocs/private> Order Deny,Allow Deny from 192.168.0.2 192.168.0.5 </Directory>
Conversely to what was explained in the previous section, it is possible to allow general access but deny access when the request comes from a specific IP address or range of IP addresses. This is useful, for example, to block specific machines or web crawlers that have been a source of problems or bandwidth abuse.
This example will allow access to the directory /usr/local/apache2/htdocs/private
and its subdirectories to anybody except clients with the IP addresses 192.168.0.2 and 192.168.0.5.
Allow
and Deny
can also restrict access based on the presence of an environment variable, as explained in the “Restricting Access Based on the Browser Type” section, later in this chapter.
Chapter 9 deals with additional ways of restricting or slowing down access to misbehaving clients.
<Location /restricted> Allow from 192.168.200.0/255.255.255.0 AuthType Basic AuthUserFile /usr/local/apache2/conf/htusers AuthName "Restricted Resource" AuthAuthoritative on Require valid-user Satisfy any </Location>
You can combine different access control methods using the Satisfy
directive. For example, the configuration shown here requires users to either come from an internal, authorized address OR provide a valid username and password.
If you would like to require both that user come from a certain internal address AND provide a valid username and password, you will need to use Satisfy all
.
When a request gets an access denied response from the web server, the user will be presented with a hardcoded server-generated error message. You can customize the message the user receives using the ErrorDocument
directive in three different ways:
You can show the user a custom message, as in the following example
ErrorDocument 403 "You do not have permission to access this file"
ErrorDocument 403 "You do not have permission to access this file
if you are using Apache 1.3 (notice that there is only one double-quote, at the beginning of the string).
Alternatively, you can redirect the request to a local URL-path with a custom message:
ErrorDocument 401 /login_failed.html
In this case, the file passed to the directive as the second argument is a path starting with a slash (/), relative to the value specified in the directive DocumentRoot
.
Finally, you can redirect the request to an external URL:
ErrorDocument 404 http://www.example.com/page _not_found.html
These examples referred to different 400 HTTP return codes, which indicate there was an error resolving the request, such as the user not providing a correct username and password. You can of course do the same for other common HTTP codes such as internal server errors. You can find a complete listing of HTTP return codes in the appendix.
Some versions of Microsoft Internet Explorer (MSIE) will by default ignore server-generated error messages when they are less than 512 bytes in size, so be sure to specify a message greater than that. You can learn more about this issue in this Microsoft Knowledge Base article http://support.microsoft.com/default.aspx?scid=kb;en-us;Q294807.
If you have multiple users publishing content in your Apache installation, it is very convenient to allow them to password-protect their own directories using .htaccess
files, described in Chapter 1. This mechanism has a performance penalty but relieves you of the task of providing access to or updating the Apache configuration file or user databases each time a change is required.
In the appropriate directory sections of your Apache configuration file, you will need to add
AllowOverride AuthConfig Limit
This will enable your users to create their own .htaccess
configuration files and place their own access control and authorization-related directives there.
Conversely, you can prevent per-directory configuration changes with the following global setting:
<Directory /> AllowOverride none </Directory>
This has the added bonus of improving performance, since Apache does not need to look for the existence of per-directory configuration files for each file requested. Alternatively, you could restrict the type of configuration options that are allowed. For more information, check the documentation for AllowOverride
.
There are certain types of files that we do not want our visitors to access under any circumstances, because they may contain passwords or other sensitive information. These include example backup files created by Unix text editors, per-directory configuration files, and so on. You may want to deny access to them using explicit configuration settings such as those shown here, which are included by default in the Apache configuration and deny access to .htaccess
and .htpasswd
files.
It is also possible to prevent the server from delivering unintended content by configuring it not to follow symbolic links. For this purpose, use the FollowSymLinks
and SymLinksIfOwnerMatch
arguments to the Options
directive, as described in its documentation.
You may also want to disable mod_speling
, explained in Chapter 4 as sometimes it may accidentally expose the names of files not intended for publishing when a misspelled URL could match multiple documents.
See also the section on how to restrict access to directory listings.
CGI programs can be a security risk. It is advisable that you disable CGI execution or at least restrict it to specific directories. For that purpose, do not use AddHandler
directives to globally enable CGI execution of certain file extensions.
Similarly, mod_include
allows execution of CGIs and external commands using Server Side Includes. They are disabled by default by the Options -IncludesNoExec
directive. If possible, make sure that the directories containing CGI scripts are writable only by the superuser and not by anyone else, and especially not by the user Apache is running as.
On a related note, you should make sure that, whenever possible, the document tree is read only. This will prevent an attacker from creating a file that can later be executed. An example of this would be to introduce a file containing PHP code in a PHP-enabled server. Also, make sure to password-protect DAV-enabled directories and do not make website contents available through other services such as FTP.
There are a number of ways in which you can restrict or slow down access to all or part of your website. This is useful when you do not want certain content to be available in search engines or when a misbehaving web crawler consumes too many resources. These methods are explained in detail in Chapter 9 which also covers how to avoid or minimize denial-of-service attacks. Denial-of-service attacks are designed to prevent or severely impair the ability of your server to answer your users’ requests. A number of Apache modules and settings can help to reduce in part those issues.
Apache allows you to define special index files with the DirectoryIndex
directive. When a request is made by a client that maps into a directory path, Apache looks for one of those index files (usually named index.html or home.html) and returns it to the browser. Alternatively, if no such file is found, Apache will return an HTML page containing a listing of the directory. While this is useful during development, or when making available a file repository, it can also provide the names of files that you do not want published or indexed by search engines (such as backup files). You can disable directory listings by disabling the mod_autoindex
module or using the Options
directive as shown here.
If per-directory configuration files are enabled, you can also place the example in an .htaccess
file.
Apache returns a Server:
header with every request. By default, this header includes information about the server name, version, and platform. Other modules present in the server, such as SSL, PHP, or mod_perl
, may add additional entries to the server string containing the module name and version. You can change or restrict the server header information using the ServerTokens
directive. While it is always good to minimize the amount of information about the server configuration that is leaked to the external world, changing the server string will not bring much additional security: Most automated scan and attack tools will ignore this information and just probe for vulnerable scripts and modules one after another, regardless of the version and modules reported.
RewriteEngine On RewriteCond %{HTTP_REFERER} !^http://(www.)?example.com/ [NC] RewriteCond %{HTTP_REFERER} ^http:// [NC] RewriteCond %{HTTP_REFERER} !^$ RewriteRule .(jpg|jpeg|gif|png|bmp)$ - [F]
Sometimes, people will link directly from their website to resources on your server, such as logo images and binary program files. This is called hotlinking and in certain situations, you may want to prevent this from happening. For example, a certain online-merchant realized that half its traffic (and bandwidth bill) was from other sites hotlinking to its images for credit card companies and countries.
You can prevent people from hotlinking to your images by requiring that the requests to the images come from your server. You can do so using mod_rewrite
. The example in the listing here will return a Forbidden
answer to any request made for image files (identified by their extensions in the fourth RewriteCond
line) whose HTTP_REFERER
header does not match your domain name (first RewriteCond
line). In addition, since certain browsers may not send a valid referer field or not send one at all, additional checks are performed to see that the referer field starts with http://
and is not blank (second and third RewriteCond
lines).
<Directory /home/*/public_html> AllowOverride FileInfo AuthConfig Limit Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec <Limit GET POST OPTIONS PROPFIND> Order allow,deny Allow from all </Limit> <LimitExcept GET POST OPTIONS PROPFIND> Order deny,allow Deny from all </LimitExcept> </Directory>
You can control access to your server based on the HTTP method of the request using <Limit>
and <LimitExcept>
directives. This example, taken from the default Apache configuration file, shows how to allow read-only methods and deny requests for any other methods that can modify the content of the file system, such as PUT. The <Directory>
section identifies per-user directories that can contain web pages, as explained in Chapter 8. The next two lines restrict the configuration settings that can be changed by users and other security settings. The <Limit>
section allows access by default to those HTTP methods that are read-only, such as GET
and POST
. The <LimitExcept>
section does the opposite, denying access to any other method, without explicitly having to enumerate them.
This is particularly useful in the context of allowing your users to administer their own content, as covered in Chapter 8.
SetEnvIf User-Agent ^EvilSearchEngine broken_crawler <Directory /usr/local/apache2/htdocs> Order Deny,Allow Deny from env=broken_crawler </Directory>
You can restrict access based on the browser type or any other header information or connection property by using environment variables with Allow
and Deny
.
In this case, browsers with a User-Agent
header beginning with EvilSearchEngine
will be denied access, and all others will be allowed. This is accomplished by using the SetEnvIf
directive to conditionally set an environment variable named broken_crawler if the User-Agent header of the request (first argument) matches a certain regular expression (second argument). Later on, you can conditionally apply Deny
and Allow
directives based on the existence of that environment variable, identified by an env=
prefix. Bear in mind that, although this technique will work most of the time, since the headers are sent by the client, headers cannot really be trusted.
The Order
directive controls the order of access directive processing only within each phase of the server’s configuration processing. This implies, for example, that an Allow
or Deny
directive occurring in a <Location>
section will always be evaluated after an Allow
or Deny
directive occurring in a <Directory>
section or .htaccess
file, regardless of the setting of the Order
directive.
Take into account that symbolic links and Alias
directives may affect your authentication setup. For example, your restrictions may be bypassed if your access control directives are placed inside a <Location>
container but the content is also accessible through additional URL mappings.
In addition to the main modules that provide IP-based access control and the standard basic and digest authentication, Apache bundles a number of other authentication modules, such as
mod_auth_anon
: Provides for FTP-style “anonymous” user access to file-download areas.
mod_auth_ldap
: This module, available in Apache 2 and later, allows authenticating users against an LDAP directory.
mod_ssl
: This module is covered in detail in Chapter 7 and allows you to use certificate-based client authentication.
One of the virtues of Apache is that it is modular and extensible. A number of third-party modules have been developed that allow Apache to interface with existing authentication frameworks such as Windows domains, LDAP, PAM, and NIS, and user information stored in a variety of databases such as MySQL, PostgreSQL, Oracle, and others. You can find most of those modules at http://modules.apache.org and http://freshmeat.net.
You can always manage authentication at the application level. Usually, this is accomplished by requesting the username and password in a web form and, upon validation, assigning a cookie that authenticates the user for the rest of the session. This is how popular portal and ecommerce sites manage their personalization features.
This module deserves a special mention. It is, in essence, an HTTP-level firewall. It allows you to inspect HTTP requests and perform all kind of monitoring, reporting, and access-control operations. It can detect and block common application-level attacks such as those involving SQL-injection and path transversal. You can find more information about this module at http://www.modsecurity.org.
<Location /combined> AuthType Basic AuthName "Restricted Access" AuthBasicProvider file ldap AuthUserFile /usr/local/apache2/conf/htusers AuthLDAPURL ldap://example.com/o=Sample Require valid-user </Location>
Apache 2.2 includes significant changes to how authentication and authorization are implemented in Apache. The changes mostly relate to work that was performed in existing modules to clearly separate methods (basic and digest authentication) and providers (file, LDAP, or SQL backends, for example). Before, both functions were mixed in each module’s implementation.
For example, mod_authn_file
implements authentication against text files and mod_authn_dbm
authenticates against database files. They can be combined with mod_auth_basic
and mod_auth_digest
, which in turn implement Basic and Digest HTTP authentication. Additional modules provide authorization functionality that authorizes users based on data stored in LDAP or SQL databases or files, as well as on file ownership or origin IP addresses.
Providers can be mixed and matched, as shown in the example at the beginning of this section. A new module, mod_authn_alias
, allows you to define complex authentication setups that can be referred by name elsewhere in the configuration file. This allows you for example to authenticate the same resource against two different LDAP servers.
As with any other server software, you need to keep up to date with new Apache releases, making sure you are aware of security issues and the patches or workarounds to address them. These URLs will help you with this task.
Apache announcements mailing list: http://httpd.apache.org/lists.html
Apache Security issues: http://httpd.apache.org/security_report.hml
Apache Week: http://www.apacheweek.com
Apache Security Tips: http://httpd.apache.org/docs-2.0/misc/security_tips.html
It is often said that security is a process, not a feature. To keep your Apache installation secure, you will need to keep up to date with Apache security advisories and monitor your error and access logs. Since Apache does not run isolated from its environment, you will need to do the same at the operating system and application level. In fact, most remotely exploitable problems with Apache are due to problems at the application level, such as vulnerable wiki, PHP libraries, and components.
Having said this, the following is a step-by-step list of measures you can take to secure a default Apache installation.
The first step is to disable all modules that you are not using. If you compiled Apache with loadable module support, you can comment out the directives that load specific modules. You may need to comment out other directives present in the configuration file that relate to the disabled module. Here is a short list of the most important modules that you should remove if you are not using them, roughly in order of importance:
PHP, mod_python
, mod_mono
, mod_perl
, and any other server side language modules. Of course, you should only disable PHP if you are not using Apache to run PHP-based applications.
mod_include
, which provides Server Side Includes support.
mod_cgi
, which provides support for invoking external programs.
mod_ssl
, used to provide SSL/TLS support for securing communications between the browser and Apache.
mod_proxy
, which, if incorrectly configured, can allow outsiders to use your server to relay requests.
mod_deflate
, an Apache 2 filter for compressing output on the fly.
mod_suexec
, used to execute external programs under user IDs different from the one Apache is running as.
mod_userdir
, which allows users in Unix systems to host their own pages.
mod_rewrite
, which allows arbitrary mapping and rewriting of incoming URLs.
Additionally, in Apache 1.3 you can explicitly disable specific compiled-in modules by using the ClearModuleList
directive and then explicitly enable modules using the AddModule
directive.
Most web server-side software and development environments include sample applications and scripts for demonstration or testing purposes. While useful, these samples are usually not coded with security in mind, and can be vulnerable to several attacks, mostly related to the program not properly escaping user input. These flaws often result in an attacker being able to execute arbitrary system commands, revealing the contents of other files, or being able to modify the database.
Make sure you remove all sample scripts and demo accounts shipped with your application servers, as well as your development environment and other web-based software you may have installed.
If you do not require CGI-script support, you should disable mod_cgi
. If you require CGI support, you should limit the ability to execute scripts to specific directories. For example, you should scan your configuration for ScriptAlias
directives and Options
directives with ExecCGI
arguments and make sure they are properly configured. Make sure that directories marked as containing executable scripts are not writable by others. You may also consider using the suExec
CGI wrapper, included with Apache.
The same rationale can be applied to Server Side Includes functionality, which is provided by mod_include
and allows execution of external commands, unless disabled by Options -IncludesNoExec
.
On Unix systems, Apache is usually started as root; does a certain number of operations, such as binding to the appropriate port; and then changes its user ID to the one specified with the User
directive. Because there are certain operations performed as root, it is critical to make sure that the log and configuration files, as well as the directories containing them, are not writable by other users. Make sure directories being marked as containing executable scripts or that can contain PHP scripts are not world writable and are not accessible through FTP or WebDAV, for example.
As with CGIs, you need to disable or restrict proxy support in your Apache installation. Otherwise, an open proxy can be used to perform attacks targeted at other websites or even to relay mail spam. If you are running Apache as a reverse proxy, you can disable “regular” proxy (forward-proxy functionality) with
ProxyRequests off
The server should be configured in such a way that by default it denies access to documents on the server unless access is explicitly enabled. The following configuration snippet, extracted from the Apache Documentation, does just that:
<Directory /> Order Deny,Allow Deny from all </Directory> <Directory /usr/local/apache2/htdocs> Order Deny,Allow Allow from all </Directory>
See also earlier sections on how to disable directory listings.
3.17.181.61